Merge pull request #45892 from corhere/libn/overlay-cut-vni-list

libnetwork/drivers/overlay: parse VNI list option in O(1) memory
This commit is contained in:
Bjorn Neergaard 2023-07-06 08:38:19 -06:00 committed by GitHub
commit c9397ec8d4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 114 additions and 17 deletions

View file

@ -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 {

View file

@ -3,6 +3,8 @@ package overlayutils
import (
"fmt"
"strconv"
"strings"
"sync"
)
@ -40,3 +42,23 @@ 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) {
for {
var (
vniStr string
found bool
)
vniStr, csv, found = strings.Cut(csv, ",")
vni, err := strconv.Atoi(vniStr)
if err != nil {
return vnis, fmt.Errorf("invalid vxlan id value %q passed", vniStr)
}
vnis = append(vnis, uint32(vni))
if !found {
return vnis, nil
}
}
}

View file

@ -0,0 +1,82 @@
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))
}
})
}
t.Run("DoesNotAllocate", func(t *testing.T) {
slice := make([]uint32, 0, 10)
csv := "1,2,3,4,5,6,7,8,9,10"
want := []uint32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
allocs := testing.AllocsPerRun(10, func() {
var err error
slice, err = AppendVNIList(slice[:0], csv)
if err != nil {
t.Fatal(err)
}
})
assert.Check(t, is.DeepEqual(slice, want))
assert.Check(t, is.Equal(int(allocs), 0))
})
}

View file

@ -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