Skip to content

Commit 00cea61

Browse files
committed
fix: Fix Invalid iproute2 JSON output in arm64
1 parent 3671320 commit 00cea61

File tree

2 files changed

+73
-0
lines changed

2 files changed

+73
-0
lines changed

src/k8s/pkg/utils/netlink.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"net"
77
"os/exec"
8+
"regexp"
89
)
910

1011
type VXLANInterface struct {
@@ -30,6 +31,11 @@ func ListVXLANInterfaces() ([]VXLANInterface, error) {
3031
return vxlanDevices, fmt.Errorf("running ip command failed: %s", string(out))
3132
}
3233

34+
out, err = fixInvalidIproute2JSON(out)
35+
if err != nil {
36+
return vxlanDevices, fmt.Errorf("failed to fix invalid VXLAN VNI: %w", err)
37+
}
38+
3339
if err := json.Unmarshal(out, &ipLinks); err != nil {
3440
return vxlanDevices, fmt.Errorf("unmarshaling ip command output failed: %w", err)
3541
}
@@ -63,3 +69,21 @@ func RemoveLink(name string) error {
6369

6470
return nil
6571
}
72+
73+
// fixInvalidIproute2JSON cleans up invalid JSON output produced by the
74+
// iproute2 command in arm64. Currently, the Ubuntu package combines the VXLAN
75+
// VNI value with the fan-map extension, resulting in invalid JSON.
76+
func fixInvalidIproute2JSON(input []byte) ([]byte, error) {
77+
output := string(input)
78+
79+
// Target the specific case where numeric VXLAN VNI values are concatenated
80+
// with text (like "0fan-map") without proper JSON quoting
81+
re, err := regexp.Compile(`"id":\s*([0-9]+[a-zA-Z][a-zA-Z0-9_-]*)`)
82+
if err != nil {
83+
return nil, fmt.Errorf("failed to compile invalid VXLAN VNI regexp: %w", err)
84+
}
85+
86+
// Enclose the entire VNI value in double quotes
87+
output = re.ReplaceAllString(output, `"id":"$1"`)
88+
return []byte(output), nil
89+
}

src/k8s/pkg/utils/netlink_test.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package utils
2+
3+
import (
4+
"bytes"
5+
"testing"
6+
)
7+
8+
func TestFixInvalidIproute2JSON(t *testing.T) {
9+
tests := []struct {
10+
name string
11+
input []byte
12+
expected []byte
13+
wantErr bool
14+
}{
15+
{
16+
name: "Valid JSON with no changes needed",
17+
input: []byte(`[
18+
{"ifindex":4,"info_data":{"id":0,"fan-map":"example"}}
19+
]`),
20+
expected: []byte(`[
21+
{"ifindex":4,"info_data":{"id":0,"fan-map":"example"}}
22+
]`),
23+
wantErr: false,
24+
},
25+
{
26+
name: "Invalid JSON with VXLAN VNI combined with fan-map",
27+
input: []byte(`[
28+
{"ifindex":4,"info_data":{"id":0fan-map,"fan-map":"example"}}
29+
]`),
30+
expected: []byte(`[
31+
{"ifindex":4,"info_data":{"id":"0fan-map","fan-map":"example"}}
32+
]`),
33+
wantErr: false,
34+
},
35+
}
36+
37+
for _, tt := range tests {
38+
t.Run(tt.name, func(t *testing.T) {
39+
output, err := fixInvalidIproute2JSON(tt.input)
40+
if (err != nil) != tt.wantErr {
41+
t.Errorf("fixInvalidIproute2JSON() error = %v, wantErr %v", err, tt.wantErr)
42+
return
43+
}
44+
if !bytes.Equal(output, tt.expected) {
45+
t.Errorf("fixInvalidIproute2JSON() = %s, expected %s", output, tt.expected)
46+
}
47+
})
48+
}
49+
}

0 commit comments

Comments
 (0)