diff --git a/netlink/netlink.go b/netlink/netlink.go index dd9b1c16..90883660 100644 --- a/netlink/netlink.go +++ b/netlink/netlink.go @@ -11,8 +11,9 @@ import ( ) var ( - ErrWrongSockType = errors.New("Wrong socket type") - ErrShortResponse = errors.New("Got short response from netlink") + ErrWrongSockType = errors.New("Wrong socket type") + ErrShortResponse = errors.New("Got short response from netlink") + ErrInterfaceExists = errors.New("Network interface already exists") ) // A Route is a subnet associated with the interface to reach it. diff --git a/netlink/netlink_linux.go b/netlink/netlink_linux.go index 738af879..3083cf90 100644 --- a/netlink/netlink_linux.go +++ b/netlink/netlink_linux.go @@ -6,6 +6,7 @@ import ( "io" "math/rand" "net" + "os" "sync/atomic" "syscall" "unsafe" @@ -708,7 +709,16 @@ func NetworkCreateVethPair(name1, name2 string) error { if err := s.Send(wb); err != nil { return err } - return s.HandleAck(wb.Seq) + + if err := s.HandleAck(wb.Seq); err != nil { + if os.IsExist(err) { + return ErrInterfaceExists + } + + return err + } + + return nil } // Add a new VLAN interface with masterDev as its upper device diff --git a/network/veth.go b/network/veth.go index a95bcf48..e5185de7 100644 --- a/network/veth.go +++ b/network/veth.go @@ -5,6 +5,7 @@ package network import ( "fmt" + "github.com/docker/libcontainer/netlink" "github.com/docker/libcontainer/utils" ) @@ -96,16 +97,25 @@ func (v *Veth) Initialize(config *Network, networkState *NetworkState) error { // createVethPair will automatically generage two random names for // the veth pair and ensure that they have been created func createVethPair(prefix string) (name1 string, name2 string, err error) { - name1, err = utils.GenerateRandomName(prefix, 4) - if err != nil { - return - } - name2, err = utils.GenerateRandomName(prefix, 4) - if err != nil { - return - } - if err = CreateVethPair(name1, name2); err != nil { - return + for i := 0; i < 10; i++ { + if name1, err = utils.GenerateRandomName(prefix, 7); err != nil { + return + } + + if name2, err = utils.GenerateRandomName(prefix, 7); err != nil { + return + } + + if err = CreateVethPair(name1, name2); err != nil { + if err == netlink.ErrInterfaceExists { + continue + } + + return + } + + break } + return } diff --git a/network/veth_test.go b/network/veth_test.go new file mode 100644 index 00000000..e09a6042 --- /dev/null +++ b/network/veth_test.go @@ -0,0 +1,53 @@ +// +build linux + +package network + +import ( + "testing" + + "github.com/docker/libcontainer/netlink" +) + +func TestGenerateVethNames(t *testing.T) { + if testing.Short() { + return + } + + prefix := "veth" + + name1, name2, err := createVethPair(prefix) + if err != nil { + t.Fatal(err) + } + + if name1 == "" { + t.Fatal("name1 should not be empty") + } + + if name2 == "" { + t.Fatal("name2 should not be empty") + } +} + +func TestCreateDuplicateVethPair(t *testing.T) { + if testing.Short() { + return + } + + prefix := "veth" + + name1, name2, err := createVethPair(prefix) + if err != nil { + t.Fatal(err) + } + + // retry to create the name interfaces and make sure that we get the correct error + err = CreateVethPair(name1, name2) + if err == nil { + t.Fatal("expected error to not be nil with duplicate interface") + } + + if err != netlink.ErrInterfaceExists { + t.Fatalf("expected error to be ErrInterfaceExists but received %q", err) + } +}