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

kubeovn / kube-ovn / 19752647265

28 Nov 2025 02:48AM UTC coverage: 22.261% (+0.001%) from 22.26%
19752647265

push

github

web-flow
feat: support selecting specific node IP for overlay subnet encapsula… (#5946)

* feat: support selecting specific node IP for overlay subnet encapsulation

Signed-off-by: Mengxin Liu <liumengxinfly@gmail.com>

28 of 157 new or added lines in 5 files covered. (17.83%)

1 existing line in 1 file now uncovered.

11437 of 51378 relevant lines covered (22.26%)

0.26 hits per line

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

0.0
/pkg/daemon/handler.go
1
package daemon
2

3
import (
4
        "context"
5
        "encoding/json"
6
        "fmt"
7
        "net"
8
        "net/http"
9
        "strconv"
10
        "strings"
11
        "time"
12

13
        "github.com/emicklei/go-restful/v3"
14
        v1 "k8s.io/api/core/v1"
15
        k8serrors "k8s.io/apimachinery/pkg/api/errors"
16
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
17
        "k8s.io/apimachinery/pkg/labels"
18
        "k8s.io/client-go/kubernetes"
19
        "k8s.io/klog/v2"
20

21
        kubeovnv1 "github.com/kubeovn/kube-ovn/pkg/apis/kubeovn/v1"
22
        clientset "github.com/kubeovn/kube-ovn/pkg/client/clientset/versioned"
23
        "github.com/kubeovn/kube-ovn/pkg/ovs"
24
        "github.com/kubeovn/kube-ovn/pkg/request"
25
        "github.com/kubeovn/kube-ovn/pkg/util"
26
)
27

28
const (
29
        gatewayCheckModeDisabled = iota
30
        gatewayCheckModePing
31
        gatewayCheckModeArping
32
        gatewayCheckModePingNotConcerned
33
        gatewayCheckModeArpingNotConcerned
34
)
35

36
type cniServerHandler struct {
37
        Config        *Configuration
38
        KubeClient    kubernetes.Interface
39
        KubeOvnClient clientset.Interface
40
        Controller    *Controller
41
}
42

43
func createCniServerHandler(config *Configuration, controller *Controller) *cniServerHandler {
×
44
        csh := &cniServerHandler{KubeClient: config.KubeClient, KubeOvnClient: config.KubeOvnClient, Config: config, Controller: controller}
×
45
        return csh
×
46
}
×
47

48
func (csh cniServerHandler) providerExists(provider string) (*kubeovnv1.Subnet, bool) {
×
49
        if util.IsOvnProvider(provider) {
×
50
                return nil, true
×
51
        }
×
52
        subnets, _ := csh.Controller.subnetsLister.List(labels.Everything())
×
53
        for _, subnet := range subnets {
×
54
                if subnet.Spec.Provider == provider {
×
55
                        return subnet.DeepCopy(), true
×
56
                }
×
57
        }
58
        return nil, false
×
59
}
60

61
func (csh cniServerHandler) handleAdd(req *restful.Request, resp *restful.Response) {
×
62
        podRequest := request.CniRequest{}
×
63
        if err := req.ReadEntity(&podRequest); err != nil {
×
64
                errMsg := fmt.Errorf("parse add request failed %w", err)
×
65
                klog.Error(errMsg)
×
66
                if err := resp.WriteHeaderAndEntity(http.StatusBadRequest, request.CniResponse{Err: errMsg.Error()}); err != nil {
×
67
                        klog.Errorf("failed to write response, %v", err)
×
68
                }
×
69
                return
×
70
        }
71
        klog.V(5).Infof("request body is %v", podRequest)
×
72
        podSubnet, exist := csh.providerExists(podRequest.Provider)
×
73
        if !exist {
×
74
                errMsg := fmt.Errorf("provider %s not bind to any subnet", podRequest.Provider)
×
75
                klog.Error(errMsg)
×
76
                if err := resp.WriteHeaderAndEntity(http.StatusBadRequest, request.CniResponse{Err: errMsg.Error()}); err != nil {
×
77
                        klog.Errorf("failed to write response, %v", err)
×
78
                }
×
79
                return
×
80
        }
81

82
        klog.Infof("add port request: %v", podRequest)
×
83
        if err := csh.validatePodRequest(&podRequest); err != nil {
×
84
                klog.Error(err)
×
85
                if err := resp.WriteHeaderAndEntity(http.StatusBadRequest, request.CniResponse{Err: err.Error()}); err != nil {
×
86
                        klog.Errorf("failed to write response, %v", err)
×
87
                }
×
88
                return
×
89
        }
90

91
        var gatewayCheckMode int
×
92
        var macAddr, ip, ipAddr, cidr, gw, subnet, ingress, egress, providerNetwork, ifName, nicType, podNicName, vmName, latency, limit, loss, jitter, u2oInterconnectionIP, oldPodName string
×
93
        var routes []request.Route
×
94
        var isDefaultRoute bool
×
95
        var pod *v1.Pod
×
96
        var err error
×
97
        for range 20 {
×
98
                if pod, err = csh.Controller.podsLister.Pods(podRequest.PodNamespace).Get(podRequest.PodName); err != nil {
×
99
                        errMsg := fmt.Errorf("get pod %s/%s failed %w", podRequest.PodNamespace, podRequest.PodName, err)
×
100
                        klog.Error(errMsg)
×
101
                        if err := resp.WriteHeaderAndEntity(http.StatusInternalServerError, request.CniResponse{Err: errMsg.Error()}); err != nil {
×
102
                                klog.Errorf("failed to write response, %v", err)
×
103
                        }
×
104
                        return
×
105
                }
106
                if pod.Annotations[fmt.Sprintf(util.AllocatedAnnotationTemplate, podRequest.Provider)] != "true" {
×
107
                        klog.Infof("wait address for pod %s/%s provider %s", podRequest.PodNamespace, podRequest.PodName, podRequest.Provider)
×
108
                        // wait controller assign an address
×
109
                        cniWaitAddressResult.WithLabelValues(nodeName).Inc()
×
110
                        time.Sleep(1 * time.Second)
×
111
                        continue
×
112
                }
113

114
                if err := util.ValidatePodNetwork(pod.Annotations); err != nil {
×
115
                        klog.Errorf("validate pod %s/%s failed, %v", podRequest.PodNamespace, podRequest.PodName, err)
×
116
                        // wait controller assign an address
×
117
                        cniWaitAddressResult.WithLabelValues(nodeName).Inc()
×
118
                        time.Sleep(1 * time.Second)
×
119
                        continue
×
120
                }
121
                ip = pod.Annotations[fmt.Sprintf(util.IPAddressAnnotationTemplate, podRequest.Provider)]
×
122
                cidr = pod.Annotations[fmt.Sprintf(util.CidrAnnotationTemplate, podRequest.Provider)]
×
123
                gw = pod.Annotations[fmt.Sprintf(util.GatewayAnnotationTemplate, podRequest.Provider)]
×
124
                subnet = pod.Annotations[fmt.Sprintf(util.LogicalSwitchAnnotationTemplate, podRequest.Provider)]
×
125
                ingress = pod.Annotations[fmt.Sprintf(util.IngressRateAnnotationTemplate, podRequest.Provider)]
×
126
                egress = pod.Annotations[fmt.Sprintf(util.EgressRateAnnotationTemplate, podRequest.Provider)]
×
127
                latency = pod.Annotations[fmt.Sprintf(util.NetemQosLatencyAnnotationTemplate, podRequest.Provider)]
×
128
                limit = pod.Annotations[fmt.Sprintf(util.NetemQosLimitAnnotationTemplate, podRequest.Provider)]
×
129
                loss = pod.Annotations[fmt.Sprintf(util.NetemQosLossAnnotationTemplate, podRequest.Provider)]
×
130
                jitter = pod.Annotations[fmt.Sprintf(util.NetemQosJitterAnnotationTemplate, podRequest.Provider)]
×
131
                providerNetwork = pod.Annotations[fmt.Sprintf(util.ProviderNetworkTemplate, podRequest.Provider)]
×
132
                vmName = pod.Annotations[fmt.Sprintf(util.VMAnnotationTemplate, podRequest.Provider)]
×
133
                ipAddr, err = util.GetIPAddrWithMask(ip, cidr)
×
134
                if err != nil {
×
135
                        errMsg := fmt.Errorf("failed to get ip address with mask, %w", err)
×
136
                        klog.Error(errMsg)
×
137
                        if err := resp.WriteHeaderAndEntity(http.StatusInternalServerError, request.CniResponse{Err: errMsg.Error()}); err != nil {
×
138
                                klog.Errorf("failed to write response, %v", err)
×
139
                        }
×
140
                        return
×
141
                }
142
                oldPodName = podRequest.PodName
×
143
                if s := pod.Annotations[fmt.Sprintf(util.RoutesAnnotationTemplate, podRequest.Provider)]; s != "" {
×
144
                        if err = json.Unmarshal([]byte(s), &routes); err != nil {
×
145
                                errMsg := fmt.Errorf("invalid routes for pod %s/%s: %w", pod.Namespace, pod.Name, err)
×
146
                                klog.Error(errMsg)
×
147
                                if err = resp.WriteHeaderAndEntity(http.StatusInternalServerError, request.CniResponse{Err: errMsg.Error()}); err != nil {
×
148
                                        klog.Errorf("failed to write response: %v", err)
×
149
                                }
×
150
                                return
×
151
                        }
152
                }
153
                if ifName = podRequest.IfName; ifName == "" {
×
154
                        ifName = "eth0"
×
155
                }
×
156

157
                // For Support kubevirt hotplug dpdk nic, forbidden set the volume name
158
                if podRequest.VhostUserSocketConsumption == util.ConsumptionKubevirt {
×
159
                        podRequest.VhostUserSocketVolumeName = util.VhostUserSocketVolumeName
×
160
                }
×
161

162
                switch {
×
163
                case podRequest.DeviceID != "":
×
164
                        nicType = util.OffloadType
×
165
                case podRequest.VhostUserSocketVolumeName != "":
×
166
                        nicType = util.DpdkType
×
167
                        if err = createShortSharedDir(pod, podRequest.VhostUserSocketVolumeName, podRequest.VhostUserSocketConsumption, csh.Config.KubeletDir); err != nil {
×
168
                                klog.Error(err.Error())
×
169
                                if err = resp.WriteHeaderAndEntity(http.StatusInternalServerError, request.CniResponse{Err: err.Error()}); err != nil {
×
170
                                        klog.Errorf("failed to write response: %v", err)
×
171
                                }
×
172
                                return
×
173
                        }
174
                default:
×
175
                        nicType = pod.Annotations[fmt.Sprintf(util.PodNicAnnotationTemplate, podRequest.Provider)]
×
176
                }
177

178
                switch pod.Annotations[fmt.Sprintf(util.DefaultRouteAnnotationTemplate, podRequest.Provider)] {
×
179
                case "true":
×
180
                        isDefaultRoute = true
×
181
                case "false":
×
182
                        isDefaultRoute = false
×
183
                default:
×
184
                        isDefaultRoute = ifName == "eth0"
×
185
                }
186

187
                if isDefaultRoute && pod.Annotations[fmt.Sprintf(util.RoutedAnnotationTemplate, podRequest.Provider)] != "true" && util.IsOvnProvider(podRequest.Provider) {
×
188
                        klog.Infof("wait route ready for pod %s/%s provider %s", podRequest.PodNamespace, podRequest.PodName, podRequest.Provider)
×
189
                        cniWaitRouteResult.WithLabelValues(nodeName).Inc()
×
190
                        time.Sleep(1 * time.Second)
×
191
                        continue
×
192
                }
193

194
                if vmName != "" {
×
195
                        podRequest.PodName = vmName
×
196
                }
×
197

198
                break
×
199
        }
200

201
        if pod.Annotations[fmt.Sprintf(util.AllocatedAnnotationTemplate, podRequest.Provider)] != "true" {
×
202
                err := fmt.Errorf("no address allocated to pod %s/%s provider %s, please see kube-ovn-controller logs to find errors", pod.Namespace, pod.Name, podRequest.Provider)
×
203
                klog.Error(err)
×
204
                if err := resp.WriteHeaderAndEntity(http.StatusInternalServerError, request.CniResponse{Err: err.Error()}); err != nil {
×
205
                        klog.Errorf("failed to write response, %v", err)
×
206
                }
×
207
                return
×
208
        }
209

210
        if subnet == "" && podSubnet != nil {
×
211
                subnet = podSubnet.Name
×
212
        }
×
213
        if err := csh.UpdateIPCR(podRequest, subnet, ip); err != nil {
×
214
                if err := resp.WriteHeaderAndEntity(http.StatusInternalServerError, request.CniResponse{Err: err.Error()}); err != nil {
×
215
                        klog.Errorf("failed to write response, %v", err)
×
216
                }
×
217
                return
×
218
        }
219

220
        if isDefaultRoute && pod.Annotations[fmt.Sprintf(util.RoutedAnnotationTemplate, podRequest.Provider)] != "true" && util.IsOvnProvider(podRequest.Provider) {
×
221
                err := fmt.Errorf("route is not ready for pod %s/%s provider %s, please see kube-ovn-controller logs to find errors", pod.Namespace, pod.Name, podRequest.Provider)
×
222
                klog.Error(err)
×
223
                if err := resp.WriteHeaderAndEntity(http.StatusInternalServerError, request.CniResponse{Err: err.Error()}); err != nil {
×
224
                        klog.Errorf("failed to write response, %v", err)
×
225
                }
×
226
                return
×
227
        }
228

229
        var mtu int
×
230
        routes = append(podRequest.Routes, routes...)
×
231
        if strings.HasSuffix(podRequest.Provider, util.OvnProvider) && subnet != "" {
×
232
                podSubnet, err := csh.Controller.subnetsLister.Get(subnet)
×
233
                if err != nil {
×
234
                        errMsg := fmt.Errorf("failed to get subnet %s: %w", subnet, err)
×
235
                        klog.Error(errMsg)
×
236
                        if err = resp.WriteHeaderAndEntity(http.StatusInternalServerError, request.CniResponse{Err: errMsg.Error()}); err != nil {
×
237
                                klog.Errorf("failed to write response: %v", err)
×
238
                        }
×
239
                        return
×
240
                }
241

242
                if podSubnet.Status.U2OInterconnectionIP == "" && podSubnet.Spec.U2OInterconnection {
×
243
                        errMsg := fmt.Errorf("failed to generate u2o ip on subnet %s", podSubnet.Name)
×
244
                        klog.Error(errMsg)
×
245
                        return
×
246
                }
×
247

248
                if podSubnet.Status.U2OInterconnectionIP != "" && podSubnet.Spec.U2OInterconnection {
×
249
                        u2oInterconnectionIP = podSubnet.Status.U2OInterconnectionIP
×
250
                }
×
251

252
                var vmMigration bool
×
253
                subnetHasVlan := podSubnet.Spec.Vlan != ""
×
254
                // skip ping check gateway for pods during live migration
×
255
                if pod.Annotations[util.MigrationJobAnnotation] == "" {
×
256
                        if subnetHasVlan && !podSubnet.Spec.LogicalGateway {
×
257
                                if podSubnet.Spec.DisableGatewayCheck {
×
258
                                        gatewayCheckMode = gatewayCheckModeArpingNotConcerned
×
259
                                } else {
×
260
                                        gatewayCheckMode = gatewayCheckModeArping
×
261
                                }
×
262
                        } else {
×
263
                                if podSubnet.Spec.DisableGatewayCheck {
×
264
                                        gatewayCheckMode = gatewayCheckModePingNotConcerned
×
265
                                } else {
×
266
                                        gatewayCheckMode = gatewayCheckModePing
×
267
                                }
×
268
                        }
269
                } else {
×
270
                        vmMigration = true
×
271
                }
×
272
                if pod.Annotations[fmt.Sprintf(util.ActivationStrategyTemplate, podRequest.Provider)] != "" {
×
273
                        gatewayCheckMode = gatewayCheckModeDisabled
×
274
                }
×
275

276
                if podSubnet.Spec.Mtu > 0 {
×
277
                        mtu = int(podSubnet.Spec.Mtu)
×
278
                } else {
×
279
                        if providerNetwork != "" && !podSubnet.Spec.LogicalGateway && !podSubnet.Spec.U2OInterconnection {
×
280
                                node, err := csh.Controller.nodesLister.Get(csh.Config.NodeName)
×
281
                                if err != nil {
×
282
                                        errMsg := fmt.Errorf("failed to get node %s: %w", csh.Config.NodeName, err)
×
283
                                        klog.Error(errMsg)
×
284
                                        if err = resp.WriteHeaderAndEntity(http.StatusInternalServerError, request.CniResponse{Err: errMsg.Error()}); err != nil {
×
285
                                                klog.Errorf("failed to write response: %v", err)
×
286
                                        }
×
287
                                        return
×
288
                                }
289
                                mtuStr := node.Labels[fmt.Sprintf(util.ProviderNetworkMtuTemplate, providerNetwork)]
×
290
                                if mtuStr != "" {
×
291
                                        if mtu, err = strconv.Atoi(mtuStr); err != nil || mtu <= 0 {
×
292
                                                errMsg := fmt.Errorf("failed to parse provider network MTU %s: %w", mtuStr, err)
×
293
                                                klog.Error(errMsg)
×
294
                                                if err = resp.WriteHeaderAndEntity(http.StatusInternalServerError, request.CniResponse{Err: errMsg.Error()}); err != nil {
×
295
                                                        klog.Errorf("failed to write response: %v", err)
×
296
                                                }
×
297
                                                return
×
298
                                        }
299
                                }
300
                        } else {
×
301
                                mtu = csh.Config.MTU
×
302
                        }
×
303
                }
304

305
                macAddr = pod.Annotations[fmt.Sprintf(util.MacAddressAnnotationTemplate, podRequest.Provider)]
×
306
                klog.Infof("create container interface %s mac %s, ip %s, cidr %s, gw %s, custom routes %v", ifName, macAddr, ipAddr, cidr, gw, routes)
×
307
                podNicName = ifName
×
NEW
308

×
NEW
309
                var encapIP string
×
NEW
310
                if podSubnet.Spec.NodeNetwork != "" {
×
NEW
311
                        encapIP, err = csh.Config.GetEncapIPByNetwork(podSubnet.Spec.NodeNetwork)
×
NEW
312
                        if err != nil {
×
NEW
313
                                errMsg := fmt.Errorf("failed to get encap IP for node network %s: %w", podSubnet.Spec.NodeNetwork, err)
×
NEW
314
                                klog.Error(errMsg)
×
NEW
315
                                if err = resp.WriteHeaderAndEntity(http.StatusInternalServerError, request.CniResponse{Err: errMsg.Error()}); err != nil {
×
NEW
316
                                        klog.Errorf("failed to write response: %v", err)
×
NEW
317
                                }
×
NEW
318
                                return
×
319
                        }
320
                }
321

322
                switch nicType {
×
323
                case util.DpdkType:
×
324
                        err = csh.configureDpdkNic(podRequest.PodName, podRequest.PodNamespace, podRequest.Provider, podRequest.NetNs, podRequest.ContainerID, ifName, macAddr, mtu, ipAddr, gw, ingress, egress, getShortSharedDir(pod.UID, podRequest.VhostUserSocketVolumeName), podRequest.VhostUserSocketName, podRequest.VhostUserSocketConsumption)
×
325
                        routes = nil
×
326
                default:
×
NEW
327
                        routes, err = csh.configureNic(podRequest.PodName, podRequest.PodNamespace, podRequest.Provider, podRequest.NetNs, podRequest.ContainerID, podRequest.VfDriver, ifName, macAddr, mtu, ipAddr, gw, isDefaultRoute, vmMigration, routes, podRequest.DNS.Nameservers, podRequest.DNS.Search, ingress, egress, podRequest.DeviceID, latency, limit, loss, jitter, gatewayCheckMode, u2oInterconnectionIP, oldPodName, encapIP)
×
328
                }
329
                if err != nil {
×
330
                        errMsg := fmt.Errorf("configure nic %s for pod %s/%s failed: %w", ifName, podRequest.PodName, podRequest.PodNamespace, err)
×
331
                        klog.Error(errMsg)
×
332
                        if err := resp.WriteHeaderAndEntity(http.StatusInternalServerError, request.CniResponse{Err: errMsg.Error()}); err != nil {
×
333
                                klog.Errorf("failed to write response, %v", err)
×
334
                        }
×
335
                        return
×
336
                }
337

338
                ifaceID := ovs.PodNameToPortName(podRequest.PodName, podRequest.PodNamespace, podRequest.Provider)
×
339
                if err = ovs.ConfigInterfaceMirror(csh.Config.EnableMirror, pod.Annotations[fmt.Sprintf(util.MirrorControlAnnotationTemplate, podRequest.Provider)], ifaceID); err != nil {
×
340
                        klog.Errorf("failed mirror to mirror0, %v", err)
×
341
                        return
×
342
                }
×
343

344
                if err = csh.Controller.addEgressConfig(podSubnet, ip); err != nil {
×
345
                        errMsg := fmt.Errorf("failed to add egress configuration: %w", err)
×
346
                        klog.Error(errMsg)
×
347
                        if err = resp.WriteHeaderAndEntity(http.StatusInternalServerError, request.CniResponse{Err: errMsg.Error()}); err != nil {
×
348
                                klog.Errorf("failed to write response, %v", err)
×
349
                        }
×
350
                        return
×
351
                }
352
        } else if len(routes) != 0 {
×
353
                hasDefaultRoute := make(map[string]bool, 2)
×
354
                for _, r := range routes {
×
355
                        if r.Destination == "" {
×
356
                                hasDefaultRoute[util.CheckProtocol(r.Gateway)] = true
×
357
                                continue
×
358
                        }
359
                        if _, cidr, err := net.ParseCIDR(r.Destination); err == nil {
×
360
                                if ones, _ := cidr.Mask.Size(); ones == 0 {
×
361
                                        hasDefaultRoute[util.CheckProtocol(r.Gateway)] = true
×
362
                                }
×
363
                        }
364
                }
365
                if len(hasDefaultRoute) != 0 {
×
366
                        // remove existing default route so other CNI plugins, such as macvlan, can add the new default route correctly
×
367
                        if err = csh.removeDefaultRoute(podRequest.NetNs, hasDefaultRoute[kubeovnv1.ProtocolIPv4], hasDefaultRoute[kubeovnv1.ProtocolIPv6]); err != nil {
×
368
                                errMsg := fmt.Errorf("failed to remove existing default route for interface %s of pod %s/%s: %w", podRequest.IfName, podRequest.PodNamespace, podRequest.PodName, err)
×
369
                                klog.Error(errMsg)
×
370
                                if err = resp.WriteHeaderAndEntity(http.StatusInternalServerError, request.CniResponse{Err: errMsg.Error()}); err != nil {
×
371
                                        klog.Errorf("failed to write response: %v", err)
×
372
                                }
×
373
                                return
×
374
                        }
375
                }
376
        }
377

378
        response := &request.CniResponse{
×
379
                Protocol:   util.CheckProtocol(cidr),
×
380
                IPAddress:  ip,
×
381
                MacAddress: macAddr,
×
382
                CIDR:       cidr,
×
383
                PodNicName: podNicName,
×
384
                Routes:     routes,
×
385
                Mtu:        mtu,
×
386
        }
×
387
        if isDefaultRoute {
×
388
                response.Gateway = gw
×
389
        }
×
390
        if err := resp.WriteHeaderAndEntity(http.StatusOK, response); err != nil {
×
391
                klog.Errorf("failed to write response, %v", err)
×
392
        }
×
393
}
394

395
func (csh cniServerHandler) UpdateIPCR(podRequest request.CniRequest, subnet, ip string) error {
×
396
        ipCRName := ovs.PodNameToPortName(podRequest.PodName, podRequest.PodNamespace, podRequest.Provider)
×
397
        for range 20 {
×
398
                ipCR, err := csh.KubeOvnClient.KubeovnV1().IPs().Get(context.Background(), ipCRName, metav1.GetOptions{})
×
399
                if err != nil {
×
400
                        err = fmt.Errorf("failed to get ip crd for %s, %w", ip, err)
×
401
                        // maybe create a backup pod with previous annotations
×
402
                        klog.Error(err)
×
403
                } else if ipCR.Spec.NodeName != csh.Config.NodeName {
×
404
                        ipCR := ipCR.DeepCopy()
×
405
                        if ipCR.Labels == nil {
×
406
                                ipCR.Labels = map[string]string{}
×
407
                        }
×
408
                        ipCR.Spec.NodeName = csh.Config.NodeName
×
409
                        ipCR.Spec.AttachIPs = []string{}
×
410
                        ipCR.Labels[subnet] = ""
×
411
                        ipCR.Labels[util.NodeNameLabel] = csh.Config.NodeName
×
412
                        ipCR.Spec.AttachSubnets = []string{}
×
413
                        ipCR.Spec.AttachMacs = []string{}
×
414
                        if _, err := csh.KubeOvnClient.KubeovnV1().IPs().Update(context.Background(), ipCR, metav1.UpdateOptions{}); err != nil {
×
415
                                err = fmt.Errorf("failed to update ip crd for %s, %w", ip, err)
×
416
                                klog.Error(err)
×
417
                        } else {
×
418
                                return nil
×
419
                        }
×
420
                }
421
                if err != nil {
×
422
                        klog.Warningf("wait pod ip %s to be ready", ipCRName)
×
423
                        time.Sleep(1 * time.Second)
×
424
                } else {
×
425
                        return nil
×
426
                }
×
427
        }
428
        // update ip spec node is not that necessary, so we just log the error
429
        return nil
×
430
}
431

432
func (csh cniServerHandler) handleDel(req *restful.Request, resp *restful.Response) {
×
433
        var podRequest request.CniRequest
×
434
        if err := req.ReadEntity(&podRequest); err != nil {
×
435
                errMsg := fmt.Errorf("parse del request failed %w", err)
×
436
                klog.Error(errMsg)
×
437
                if err := resp.WriteHeaderAndEntity(http.StatusBadRequest, request.CniResponse{Err: errMsg.Error()}); err != nil {
×
438
                        klog.Errorf("failed to write response, %v", err)
×
439
                }
×
440
                return
×
441
        }
442

443
        // Try to get the Pod, but if it fails due to not being found, log a warning and continue.
444
        pod, err := csh.Controller.podsLister.Pods(podRequest.PodNamespace).Get(podRequest.PodName)
×
445
        if err != nil && !k8serrors.IsNotFound(err) {
×
446
                errMsg := fmt.Errorf("failed to retrieve Pod %s/%s: %w", podRequest.PodNamespace, podRequest.PodName, err)
×
447
                klog.Error(errMsg)
×
448
                if err := resp.WriteHeaderAndEntity(http.StatusBadRequest, request.CniResponse{Err: errMsg.Error()}); err != nil {
×
449
                        klog.Errorf("failed to write response, %v", err)
×
450
                }
×
451
                return
×
452
        }
453

454
        if podRequest.NetNs == "" {
×
455
                klog.Infof("skip del port request: %v", podRequest)
×
456
                resp.WriteHeader(http.StatusNoContent)
×
457
                return
×
458
        }
×
459

460
        klog.Infof("del port request: %v", podRequest)
×
461
        if err := csh.validatePodRequest(&podRequest); err != nil {
×
462
                klog.Error(err)
×
463
                if err := resp.WriteHeaderAndEntity(http.StatusBadRequest, request.CniResponse{Err: err.Error()}); err != nil {
×
464
                        klog.Errorf("failed to write response, %v", err)
×
465
                }
×
466
                return
×
467
        }
468

469
        var nicType string
×
470
        var vmName string
×
471

×
472
        // If the Pod was found, process its annotations and labels.
×
473
        if pod != nil {
×
474
                if pod.Annotations != nil && (util.IsOvnProvider(podRequest.Provider) || podRequest.CniType == util.CniTypeName) {
×
475
                        subnet := pod.Annotations[fmt.Sprintf(util.LogicalSwitchAnnotationTemplate, podRequest.Provider)]
×
476
                        if subnet != "" {
×
477
                                ip := pod.Annotations[fmt.Sprintf(util.IPAddressAnnotationTemplate, podRequest.Provider)]
×
478
                                if err = csh.Controller.removeEgressConfig(subnet, ip); err != nil {
×
479
                                        errMsg := fmt.Errorf("failed to remove egress configuration: %w", err)
×
480
                                        klog.Error(errMsg)
×
481
                                        if err = resp.WriteHeaderAndEntity(http.StatusInternalServerError, request.CniResponse{Err: errMsg.Error()}); err != nil {
×
482
                                                klog.Errorf("failed to write response, %v", err)
×
483
                                        }
×
484
                                        return
×
485
                                }
486
                        }
487

488
                        switch {
×
489
                        case podRequest.DeviceID != "":
×
490
                                nicType = util.OffloadType
×
491
                        case podRequest.VhostUserSocketVolumeName != "":
×
492
                                nicType = util.DpdkType
×
493
                                if err = removeShortSharedDir(pod, podRequest.VhostUserSocketVolumeName, podRequest.VhostUserSocketConsumption); err != nil {
×
494
                                        klog.Error(err.Error())
×
495
                                        if err = resp.WriteHeaderAndEntity(http.StatusInternalServerError, request.CniResponse{Err: err.Error()}); err != nil {
×
496
                                                klog.Errorf("failed to write response: %v", err)
×
497
                                        }
×
498
                                        return
×
499
                                }
500
                        default:
×
501
                                nicType = pod.Annotations[fmt.Sprintf(util.PodNicAnnotationTemplate, podRequest.Provider)]
×
502
                        }
503

504
                        vmName = pod.Annotations[fmt.Sprintf(util.VMAnnotationTemplate, podRequest.Provider)]
×
505
                        if vmName != "" {
×
506
                                podRequest.PodName = vmName
×
507
                        }
×
508
                }
509
        } else {
×
510
                // If the Pod is not found, assign a default value.
×
511
                klog.Warningf("Pod %s not found, proceeding with NIC deletion using ContainerID and NetNs", podRequest.PodName)
×
512
                switch {
×
513
                case podRequest.DeviceID != "":
×
514
                        nicType = util.OffloadType
×
515
                case podRequest.VhostUserSocketVolumeName != "":
×
516
                        nicType = util.DpdkType
×
517
                default:
×
518
                        nicType = util.VethType
×
519
                }
520
        }
521

522
        // For Support kubevirt hotplug dpdk nic, forbidden set the volume name
523
        if podRequest.VhostUserSocketConsumption == util.ConsumptionKubevirt {
×
524
                podRequest.VhostUserSocketVolumeName = util.VhostUserSocketVolumeName
×
525
        }
×
526

527
        // Proceed to delete the NIC regardless of whether the Pod was found or not.
528
        err = csh.deleteNic(podRequest.PodName, podRequest.PodNamespace, podRequest.ContainerID, podRequest.NetNs, podRequest.DeviceID, podRequest.IfName, nicType)
×
529
        if err != nil {
×
530
                errMsg := fmt.Errorf("del nic failed %w", err)
×
531
                klog.Error(errMsg)
×
532
                if err := resp.WriteHeaderAndEntity(http.StatusInternalServerError, request.CniResponse{Err: errMsg.Error()}); err != nil {
×
533
                        klog.Errorf("failed to write response, %v", err)
×
534
                }
×
535
                return
×
536
        }
537
        resp.WriteHeader(http.StatusNoContent)
×
538
}
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