diff --git a/libnetwork/drivers/overlay/ov_network.go b/libnetwork/drivers/overlay/ov_network.go index 4de485ddc9..8b712808b4 100644 --- a/libnetwork/drivers/overlay/ov_network.go +++ b/libnetwork/drivers/overlay/ov_network.go @@ -16,6 +16,7 @@ import ( "github.com/containerd/containerd/log" "github.com/docker/docker/libnetwork/driverapi" + "github.com/docker/docker/libnetwork/drivers/overlay/overlayutils" "github.com/docker/docker/libnetwork/netlabel" "github.com/docker/docker/libnetwork/ns" "github.com/docker/docker/libnetwork/osl" @@ -111,14 +112,10 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo d return errors.New("no VNI provided") } log.G(context.TODO()).Debugf("overlay: Received vxlan IDs: %s", vnisOpt) - vniStrings := strings.Split(vnisOpt, ",") - for _, vniStr := range vniStrings { - vni, err := strconv.Atoi(vniStr) - if err != nil { - return fmt.Errorf("invalid vxlan id value %q passed", vniStr) - } - - vnis = append(vnis, uint32(vni)) + var err error + vnis, err = overlayutils.AppendVNIList(vnis, vnisOpt) + if err != nil { + return err } if _, ok := optMap[secureOption]; ok { diff --git a/libnetwork/drivers/overlay/overlayutils/utils.go b/libnetwork/drivers/overlay/overlayutils/utils.go index 2d7674a535..a76afb0766 100644 --- a/libnetwork/drivers/overlay/overlayutils/utils.go +++ b/libnetwork/drivers/overlay/overlayutils/utils.go @@ -3,6 +3,8 @@ package overlayutils import ( "fmt" + "strconv" + "strings" "sync" ) @@ -40,3 +42,17 @@ func VXLANUDPPort() uint32 { defer mutex.RUnlock() return vxlanUDPPort } + +// AppendVNIList appends the VNI values encoded as a CSV string to slice. +func AppendVNIList(vnis []uint32, csv string) ([]uint32, error) { + vniStrings := strings.Split(csv, ",") + for _, vniStr := range vniStrings { + vni, err := strconv.Atoi(vniStr) + if err != nil { + return vnis, fmt.Errorf("invalid vxlan id value %q passed", vniStr) + } + + vnis = append(vnis, uint32(vni)) + } + return vnis, nil +} diff --git a/libnetwork/drivers/overlay/overlayutils/utils_test.go b/libnetwork/drivers/overlay/overlayutils/utils_test.go new file mode 100644 index 0000000000..45d4c19dab --- /dev/null +++ b/libnetwork/drivers/overlay/overlayutils/utils_test.go @@ -0,0 +1,67 @@ +package overlayutils + +import ( + "testing" + + "gotest.tools/v3/assert" + is "gotest.tools/v3/assert/cmp" +) + +func TestAppendVNIList(t *testing.T) { + cases := []struct { + name string + slice []uint32 + csv string + want []uint32 + wantErr string + }{ + { + name: "NilSlice", + csv: "1,2,3", + want: []uint32{1, 2, 3}, + }, + { + name: "TrailingComma", + csv: "1,2,3,", + want: []uint32{1, 2, 3}, + wantErr: `invalid vxlan id value "" passed`, + }, + { + name: "EmptySlice", + slice: make([]uint32, 0, 10), + csv: "1,2,3", + want: []uint32{1, 2, 3}, + }, + { + name: "ExistingSlice", + slice: []uint32{4, 5, 6}, + csv: "1,2,3", + want: []uint32{4, 5, 6, 1, 2, 3}, + }, + { + name: "InvalidVNI", + slice: []uint32{4, 5, 6}, + csv: "1,2,3,abc", + want: []uint32{4, 5, 6, 1, 2, 3}, + wantErr: "invalid vxlan id value \"abc\" passed", + }, + { + name: "InvalidVNI2", + slice: []uint32{4, 5, 6}, + csv: "abc,1,2,3", + want: []uint32{4, 5, 6}, + wantErr: "invalid vxlan id value \"abc\" passed", + }, + } + for _, tt := range cases { + t.Run(tt.name, func(t *testing.T) { + got, err := AppendVNIList(tt.slice, tt.csv) + assert.Check(t, is.DeepEqual(tt.want, got)) + if tt.wantErr == "" { + assert.Check(t, err) + } else { + assert.Check(t, is.ErrorContains(err, tt.wantErr)) + } + }) + } +} diff --git a/libnetwork/drivers/overlay/ovmanager/ovmanager.go b/libnetwork/drivers/overlay/ovmanager/ovmanager.go index 0b4ee45eee..127496dfba 100644 --- a/libnetwork/drivers/overlay/ovmanager/ovmanager.go +++ b/libnetwork/drivers/overlay/ovmanager/ovmanager.go @@ -5,7 +5,6 @@ import ( "fmt" "net" "strconv" - "strings" "sync" "github.com/containerd/containerd/log" @@ -13,6 +12,7 @@ import ( "github.com/docker/docker/libnetwork/datastore" "github.com/docker/docker/libnetwork/discoverapi" "github.com/docker/docker/libnetwork/driverapi" + "github.com/docker/docker/libnetwork/drivers/overlay/overlayutils" "github.com/docker/docker/libnetwork/netlabel" "github.com/docker/docker/libnetwork/types" ) @@ -88,14 +88,10 @@ func (d *driver) NetworkAllocate(id string, option map[string]string, ipV4Data, for key, val := range option { if key == netlabel.OverlayVxlanIDList { log.G(context.TODO()).Debugf("overlay network option: %s", val) - valStrList := strings.Split(val, ",") - for _, idStr := range valStrList { - vni, err := strconv.Atoi(idStr) - if err != nil { - return nil, fmt.Errorf("invalid vxlan id value %q passed", idStr) - } - - vxlanIDList = append(vxlanIDList, uint32(vni)) + var err error + vxlanIDList, err = overlayutils.AppendVNIList(vxlanIDList, val) + if err != nil { + return nil, err } } else { opts[key] = val