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

kubeovn / kube-ovn / 16214662194

11 Jul 2025 07:43AM UTC coverage: 21.446% (+0.02%) from 21.425%
16214662194

Pull #5473

github

zhangzujian
export ovs functions Get/Set/Remove

Signed-off-by: zhangzujian <zhangzujian.7@gmail.com>
Pull Request #5473: export ovs functions Get/Set/Remove

17 of 48 new or added lines in 4 files covered. (35.42%)

4 existing lines in 2 files now uncovered.

10526 of 49082 relevant lines covered (21.45%)

0.25 hits per line

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

31.85
/pkg/ovs/ovs-vsctl_linux.go
1
package ovs
2

3
import (
4
        "fmt"
5
        "strconv"
6
        "strings"
7

8
        "k8s.io/klog/v2"
9

10
        "github.com/kubeovn/kube-ovn/pkg/util"
11
)
12

13
// SetInterfaceBandwidth set ingress/egress qos for given pod, annotation values are for node/pod
14
// but ingress/egress parameters here are from the point of ovs port/interface view, so reverse input parameters when call func SetInterfaceBandwidth
15
func SetInterfaceBandwidth(podName, podNamespace, iface, ingress, egress string) error {
1✔
16
        ingressMPS, _ := strconv.Atoi(ingress)
1✔
17
        ingressKPS := ingressMPS * 1000
1✔
18
        interfaceList, err := ovsFind("interface", "name", "external-ids:iface-id="+iface)
1✔
19
        if err != nil {
2✔
20
                klog.Error(err)
1✔
21
                return err
1✔
22
        }
1✔
23

24
        qosIfaceUIDMap, err := ListExternalIDs("qos")
×
25
        if err != nil {
×
26
                klog.Error(err)
×
27
                return err
×
28
        }
×
29

30
        queueIfaceUIDMap, err := ListExternalIDs("queue")
×
31
        if err != nil {
×
32
                klog.Error(err)
×
33
                return err
×
34
        }
×
35

36
        for _, ifName := range interfaceList {
×
37
                // ingress_policing_rate is in Kbps
×
NEW
38
                err := Set("interface", ifName, fmt.Sprintf("ingress_policing_rate=%d", ingressKPS), fmt.Sprintf("ingress_policing_burst=%d", ingressKPS*8/10))
×
39
                if err != nil {
×
40
                        klog.Error(err)
×
41
                        return err
×
42
                }
×
43

44
                egressMPS, _ := strconv.Atoi(egress)
×
45
                egressBPS := egressMPS * 1000 * 1000
×
46

×
47
                if egressBPS > 0 {
×
48
                        queueUID, err := SetHtbQosQueueRecord(podName, podNamespace, iface, egressBPS, queueIfaceUIDMap)
×
49
                        if err != nil {
×
50
                                klog.Error(err)
×
51
                                return err
×
52
                        }
×
53

54
                        if err = SetQosQueueBinding(podName, podNamespace, ifName, iface, queueUID, qosIfaceUIDMap); err != nil {
×
55
                                klog.Error(err)
×
56
                                return err
×
57
                        }
×
58
                } else {
×
59
                        if qosUID, ok := qosIfaceUIDMap[iface]; ok {
×
NEW
60
                                qosType, err := Get("qos", qosUID, "type", "", false)
×
61
                                if err != nil {
×
62
                                        klog.Error(err)
×
63
                                        return err
×
64
                                }
×
65
                                if qosType != util.HtbQos {
×
66
                                        continue
×
67
                                }
NEW
68
                                queueID, err := Get("qos", qosUID, "queues", "0", false)
×
69
                                if err != nil {
×
70
                                        klog.Error(err)
×
71
                                        return err
×
72
                                }
×
73

74
                                if _, err := Exec("remove", "queue", queueID, "other_config", "max-rate"); err != nil {
×
75
                                        klog.Error(err)
×
76
                                        return fmt.Errorf("failed to remove rate limit for queue in pod %v/%v, %w", podNamespace, podName, err)
×
77
                                }
×
78
                        }
79
                }
80

81
                // Delete Qos and Queue record if both bandwidth and priority do not exist
82
                if err = CheckAndUpdateHtbQos(podName, podNamespace, iface, queueIfaceUIDMap); err != nil {
×
83
                        klog.Errorf("failed to check htb qos: %v", err)
×
84
                        return err
×
85
                }
×
86
        }
87
        return nil
×
88
}
89

90
func ClearHtbQosQueue(podName, podNamespace, iface string) error {
1✔
91
        var queueList []string
1✔
92
        var err error
1✔
93
        if iface != "" {
2✔
94
                queueList, err = ovsFind("queue", "_uuid", fmt.Sprintf(`external-ids:iface-id="%s"`, iface))
1✔
95
                if err != nil {
2✔
96
                        klog.Error(err)
1✔
97
                        return err
1✔
98
                }
1✔
99
        } else {
×
100
                queueList, err = ovsFind("queue", "_uuid", fmt.Sprintf(`external-ids:pod="%s/%s"`, podNamespace, podName))
×
101
                if err != nil {
×
102
                        klog.Error(err)
×
103
                        return err
×
104
                }
×
105
        }
106

107
        // https://github.com/kubeovn/kube-ovn/issues/1191
108
        qosQueueMap, err := ListQosQueueIDs()
×
109
        if err != nil {
×
110
                klog.Error(err)
×
111
                return err
×
112
        }
×
113

114
        for _, queueID := range queueList {
×
115
                found := false
×
116
                for _, usedQueueID := range qosQueueMap {
×
117
                        if queueID == usedQueueID {
×
118
                                found = true
×
119
                                break
×
120
                        }
121
                }
122
                if found {
×
123
                        continue
×
124
                }
125

126
                if err := ovsDestroy("queue", queueID); err != nil {
×
127
                        klog.Error(err)
×
128
                        return err
×
129
                }
×
130
        }
131
        return nil
×
132
}
133

134
func IsHtbQos(iface string) (bool, error) {
1✔
135
        qosType, err := ovsFind("qos", "type", fmt.Sprintf(`external-ids:iface-id="%s"`, iface))
1✔
136
        if err != nil {
2✔
137
                klog.Error(err)
1✔
138
                return false, err
1✔
139
        }
1✔
140

141
        if len(qosType) != 0 && qosType[0] == util.HtbQos {
×
142
                return true, nil
×
143
        }
×
144
        return false, nil
×
145
}
146

147
func SetHtbQosQueueRecord(podName, podNamespace, iface string, maxRateBPS int, queueIfaceUIDMap map[string]string) (string, error) {
1✔
148
        var queueCommandValues []string
1✔
149
        var err error
1✔
150
        if maxRateBPS > 0 {
2✔
151
                queueCommandValues = append(queueCommandValues, fmt.Sprintf("other_config:max-rate=%d", maxRateBPS))
1✔
152
        }
1✔
153

154
        if queueUID, ok := queueIfaceUIDMap[iface]; ok {
2✔
155
                if err := Set("queue", queueUID, queueCommandValues...); err != nil {
2✔
156
                        klog.Error(err)
1✔
157
                        return "", err
1✔
158
                }
1✔
159
        } else {
1✔
160
                queueCommandValues = append(queueCommandValues, "external-ids:iface-id="+iface)
1✔
161
                if podNamespace != "" && podName != "" {
2✔
162
                        queueCommandValues = append(queueCommandValues, fmt.Sprintf("external-ids:pod=%s/%s", podNamespace, podName))
1✔
163
                }
1✔
164

165
                var queueID string
1✔
166
                if queueID, err = ovsCreate("queue", queueCommandValues...); err != nil {
2✔
167
                        klog.Error(err)
1✔
168
                        return "", err
1✔
169
                }
1✔
170
                queueIfaceUIDMap[iface] = queueID
×
171
        }
172

173
        return queueIfaceUIDMap[iface], nil
×
174
}
175

176
// SetQosQueueBinding set qos related to queue record.
177
func SetQosQueueBinding(podName, podNamespace, ifName, iface, queueUID string, qosIfaceUIDMap map[string]string) error {
1✔
178
        var qosCommandValues []string
1✔
179
        qosCommandValues = append(qosCommandValues, "queues:0="+queueUID)
1✔
180

1✔
181
        if qosUID, ok := qosIfaceUIDMap[iface]; !ok {
2✔
182
                qosCommandValues = append(qosCommandValues, "type=linux-htb", fmt.Sprintf(`external-ids:iface-id="%s"`, iface))
1✔
183
                if podNamespace != "" && podName != "" {
2✔
184
                        qosCommandValues = append(qosCommandValues, fmt.Sprintf("external-ids:pod=%s/%s", podNamespace, podName))
1✔
185
                }
1✔
186
                qos, err := ovsCreate("qos", qosCommandValues...)
1✔
187
                if err != nil {
2✔
188
                        klog.Error(err)
1✔
189
                        return err
1✔
190
                }
1✔
NEW
191
                err = Set("port", ifName, "qos="+qos)
×
192
                if err != nil {
×
193
                        klog.Error(err)
×
194
                        return err
×
195
                }
×
196
                qosIfaceUIDMap[iface] = qos
×
197
        } else {
1✔
198
                qosType, err := Get("qos", qosUID, "type", "", false)
1✔
199
                if err != nil {
2✔
200
                        klog.Error(err)
1✔
201
                        return err
1✔
202
                }
1✔
203
                if qosType != util.HtbQos {
×
204
                        klog.Errorf("netem qos exists for pod %s/%s, conflict with current qos, will be changed to htb qos", podNamespace, podName)
×
205
                        qosCommandValues = append(qosCommandValues, "type=linux-htb")
×
206
                }
×
207

208
                if qosType == util.HtbQos {
×
NEW
209
                        queueID, err := Get("qos", qosUID, "queues", "0", false)
×
210
                        if err != nil {
×
211
                                klog.Error(err)
×
212
                                return err
×
213
                        }
×
214
                        if queueID == queueUID {
×
215
                                return nil
×
216
                        }
×
217
                }
218

NEW
219
                if err := Set("qos", qosUID, qosCommandValues...); err != nil {
×
220
                        klog.Error(err)
×
221
                        return err
×
222
                }
×
223
        }
224
        return nil
×
225
}
226

227
// The latency value expressed in us.
228
func SetNetemQos(podName, podNamespace, iface, latency, limit, loss, jitter string) error {
1✔
229
        latencyMs, _ := strconv.Atoi(latency)
1✔
230
        latencyUs := latencyMs * 1000
1✔
231
        jitterMs, _ := strconv.Atoi(jitter)
1✔
232
        jitterUs := jitterMs * 1000
1✔
233
        limitPkts, _ := strconv.Atoi(limit)
1✔
234
        lossPercent, _ := strconv.ParseFloat(loss, 64)
1✔
235

1✔
236
        interfaceList, err := ovsFind("interface", "name", "external-ids:iface-id="+iface)
1✔
237
        if err != nil {
2✔
238
                klog.Error(err)
1✔
239
                return err
1✔
240
        }
1✔
241

242
        for _, ifName := range interfaceList {
×
243
                qosList, err := GetQosList(podName, podNamespace, iface)
×
244
                if err != nil {
×
245
                        klog.Error(err)
×
246
                        return err
×
247
                }
×
248

249
                var qosCommandValues []string
×
250
                if latencyMs > 0 {
×
251
                        qosCommandValues = append(qosCommandValues, fmt.Sprintf("other_config:latency=%d", latencyUs))
×
252
                }
×
253
                if jitterMs > 0 {
×
254
                        qosCommandValues = append(qosCommandValues, fmt.Sprintf("other_config:jitter=%d", jitterUs))
×
255
                }
×
256
                if limitPkts > 0 {
×
257
                        qosCommandValues = append(qosCommandValues, fmt.Sprintf("other_config:limit=%d", limitPkts))
×
258
                }
×
259
                if lossPercent > 0 {
×
260
                        qosCommandValues = append(qosCommandValues, fmt.Sprintf("other_config:loss=%v", lossPercent))
×
261
                }
×
262
                if latencyMs > 0 || limitPkts > 0 || lossPercent > 0 || jitterMs > 0 {
×
263
                        if len(qosList) == 0 {
×
264
                                qosCommandValues = append(qosCommandValues, "type=linux-netem", fmt.Sprintf(`external-ids:iface-id="%s"`, iface))
×
265
                                if podNamespace != "" && podName != "" {
×
266
                                        qosCommandValues = append(qosCommandValues, fmt.Sprintf("external-ids:pod=%s/%s", podNamespace, podName))
×
267
                                }
×
268

269
                                qos, err := ovsCreate("qos", qosCommandValues...)
×
270
                                if err != nil {
×
271
                                        klog.Error(err)
×
272
                                        return err
×
273
                                }
×
274

NEW
275
                                if err = Set("port", ifName, "qos="+qos); err != nil {
×
276
                                        klog.Error(err)
×
277
                                        return err
×
278
                                }
×
279
                        } else {
×
280
                                for _, qos := range qosList {
×
NEW
281
                                        qosType, err := Get("qos", qos, "type", "", false)
×
282
                                        if err != nil {
×
283
                                                klog.Error(err)
×
284
                                                return err
×
285
                                        }
×
286
                                        if qosType != util.NetemQos {
×
287
                                                klog.Errorf("htb qos with higher priority exists for pod %v/%v, conflict with netem qos config, please delete htb qos first", podNamespace, podName)
×
288
                                                return nil
×
289
                                        }
×
290

291
                                        latencyVal, lossVal, limitVal, jitterVal, err := getNetemQosConfig(qos)
×
292
                                        if err != nil {
×
293
                                                klog.Errorf("failed to get other_config for qos %s: %v", qos, err)
×
294
                                                return err
×
295
                                        }
×
296

297
                                        if latencyVal == strconv.Itoa(latencyUs) && limitVal == limit && lossVal == loss && jitterVal == strconv.Itoa(jitterUs) {
×
298
                                                klog.Infof("no value changed for netem qos, ignore")
×
299
                                                continue
×
300
                                        }
301

302
                                        if err = deleteNetemQosByID(qos, iface, podName, podNamespace); err != nil {
×
303
                                                klog.Errorf("failed to delete netem qos: %v", err)
×
304
                                                return err
×
305
                                        }
×
306

307
                                        qosCommandValues = append(qosCommandValues, "type=linux-netem", fmt.Sprintf(`external-ids:iface-id="%s"`, iface))
×
308
                                        if podNamespace != "" && podName != "" {
×
309
                                                qosCommandValues = append(qosCommandValues, fmt.Sprintf("external-ids:pod=%s/%s", podNamespace, podName))
×
310
                                        }
×
311

312
                                        qos, err := ovsCreate("qos", qosCommandValues...)
×
313
                                        if err != nil {
×
314
                                                klog.Errorf("failed to create netem qos: %v", err)
×
315
                                                return err
×
316
                                        }
×
317

NEW
318
                                        if err = Set("port", ifName, "qos="+qos); err != nil {
×
319
                                                klog.Errorf("failed to set netem qos to port: %v", err)
×
320
                                                return err
×
321
                                        }
×
322
                                }
323
                        }
324
                } else {
×
325
                        for _, qos := range qosList {
×
326
                                if err := deleteNetemQosByID(qos, iface, podName, podNamespace); err != nil {
×
327
                                        klog.Errorf("failed to delete netem qos: %v", err)
×
328
                                        return err
×
329
                                }
×
330
                        }
331
                }
332
        }
333
        return nil
×
334
}
335

336
func getNetemQosConfig(qosID string) (string, string, string, string, error) {
1✔
337
        var latency, loss, limit, jitter string
1✔
338

1✔
339
        config, err := Get("qos", qosID, "other_config", "", false)
1✔
340
        if err != nil {
2✔
341
                klog.Errorf("failed to get other_config for qos %s: %v", qosID, err)
1✔
342
                return latency, loss, limit, jitter, err
1✔
343
        }
1✔
344
        if len(config) == 0 {
×
345
                return latency, loss, limit, jitter, nil
×
346
        }
×
347

348
        values := strings.SplitSeq(strings.Trim(config, "{}"), ",")
×
349
        for value := range values {
×
350
                records := strings.Split(value, "=")
×
351
                switch strings.TrimSpace(records[0]) {
×
352
                case "latency":
×
353
                        latency = strings.TrimSpace(records[1])
×
354
                case "loss":
×
355
                        loss = strings.TrimSpace(records[1])
×
356
                case "limit":
×
357
                        limit = strings.TrimSpace(records[1])
×
358
                case "jitter":
×
359
                        jitter = strings.TrimSpace(records[1])
×
360
                }
361
        }
362
        return latency, loss, limit, jitter, nil
×
363
}
364

365
func deleteNetemQosByID(qosID, iface, podName, podNamespace string) error {
1✔
366
        qosType, _ := Get("qos", qosID, "type", "", false)
1✔
367
        if qosType != util.NetemQos {
2✔
368
                return nil
1✔
369
        }
1✔
370

371
        if err := ClearPortQosBinding(iface); err != nil {
×
372
                klog.Errorf("failed to delete qos bingding info for interface %s: %v", iface, err)
×
373
                return err
×
374
        }
×
375

376
        // reuse this function to delete qos record
377
        if err := ClearPodBandwidth(podName, podNamespace, iface); err != nil {
×
378
                klog.Errorf("failed to delete netemqos record for pod %s/%s: %v", podNamespace, podName, err)
×
379
                return err
×
380
        }
×
381
        return nil
×
382
}
383

384
func IsUserspaceDataPath() (is bool, err error) {
1✔
385
        dp, err := ovsFind("bridge", "datapath_type", "name=br-int")
1✔
386
        if err != nil {
2✔
387
                klog.Error(err)
1✔
388
                return false, err
1✔
389
        }
1✔
390
        return len(dp) > 0 && dp[0] == "netdev", nil
×
391
}
392

393
func CheckAndUpdateHtbQos(podName, podNamespace, ifaceID string, queueIfaceUIDMap map[string]string) error {
1✔
394
        var queueUID string
1✔
395
        var ok bool
1✔
396
        if queueUID, ok = queueIfaceUIDMap[ifaceID]; !ok {
2✔
397
                return nil
1✔
398
        }
1✔
399

400
        config, err := Get("queue", queueUID, "other_config", "", false)
1✔
401
        if err != nil {
2✔
402
                klog.Errorf("failed to get other_config for queueID %s: %v", queueUID, err)
1✔
403
                return err
1✔
404
        }
1✔
405
        // bandwidth or priority exists, can not delete qos
406
        if config != "{}" {
×
407
                return nil
×
408
        }
×
409

410
        if htbQos, _ := IsHtbQos(ifaceID); !htbQos {
×
411
                return nil
×
412
        }
×
413

414
        if err := ClearPortQosBinding(ifaceID); err != nil {
×
415
                klog.Errorf("failed to delete qos binding info: %v", err)
×
416
                return err
×
417
        }
×
418

419
        if err := ClearPodBandwidth(podName, podNamespace, ifaceID); err != nil {
×
420
                klog.Errorf("failed to delete htbqos record: %v", err)
×
421
                return err
×
422
        }
×
423

424
        if err := ClearHtbQosQueue(podName, podNamespace, ifaceID); err != nil {
×
425
                klog.Errorf("failed to delete htbqos queue: %v", err)
×
426
                return err
×
427
        }
×
428
        return nil
×
429
}
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

© 2025 Coveralls, Inc