diff --git a/hack/vendor.sh b/hack/vendor.sh index 3a537139fe..5bf8b601f5 100755 --- a/hack/vendor.sh +++ b/hack/vendor.sh @@ -64,7 +64,7 @@ if [ "$1" = '--go' ]; then mv tmp-tar src/code.google.com/p/go/src/pkg/archive/tar fi -clone git github.com/docker/libcontainer c744f6470e37be5ce1f1ae09b842c15c1bee120d +clone git github.com/docker/libcontainer b3570267c7b7995d5d618974d8f7be4fe5ab076a # see src/github.com/docker/libcontainer/update-vendor.sh which is the "source of truth" for libcontainer deps (just like this file) rm -rf src/github.com/docker/libcontainer/vendor eval "$(grep '^clone ' src/github.com/docker/libcontainer/update-vendor.sh | grep -v 'github.com/codegangsta/cli')" diff --git a/vendor/src/github.com/docker/libcontainer/netlink/netlink.go b/vendor/src/github.com/docker/libcontainer/netlink/netlink.go index dd9b1c1643..9088366061 100644 --- a/vendor/src/github.com/docker/libcontainer/netlink/netlink.go +++ b/vendor/src/github.com/docker/libcontainer/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/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux.go b/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux.go index 738af8798a..3083cf907a 100644 --- a/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux.go +++ b/vendor/src/github.com/docker/libcontainer/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/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux_test.go b/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux_test.go index b2bac2eb8d..88c2e04a3a 100644 --- a/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux_test.go +++ b/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux_test.go @@ -328,7 +328,7 @@ func TestCreateBridgeWithMac(t *testing.T) { } } -func TestSetMACAddress(t *testing.T) { +func TestSetMacAddress(t *testing.T) { if testing.Short() { return } diff --git a/vendor/src/github.com/docker/libcontainer/network/network.go b/vendor/src/github.com/docker/libcontainer/network/network.go index c7560c04a9..014ba74315 100644 --- a/vendor/src/github.com/docker/libcontainer/network/network.go +++ b/vendor/src/github.com/docker/libcontainer/network/network.go @@ -68,6 +68,14 @@ func SetDefaultGateway(ip, ifaceName string) error { return netlink.AddDefaultGw(ip, ifaceName) } +func SetInterfaceMac(name string, macaddr string) error { + iface, err := net.InterfaceByName(name) + if err != nil { + return err + } + return netlink.NetworkSetMacAddress(iface, macaddr) +} + func SetInterfaceIp(name string, rawIp string) error { iface, err := net.InterfaceByName(name) if err != nil { diff --git a/vendor/src/github.com/docker/libcontainer/network/types.go b/vendor/src/github.com/docker/libcontainer/network/types.go index ae098981b8..383e27c81a 100644 --- a/vendor/src/github.com/docker/libcontainer/network/types.go +++ b/vendor/src/github.com/docker/libcontainer/network/types.go @@ -17,6 +17,9 @@ type Network struct { // Prefix for the veth interfaces. VethPrefix string `json:"veth_prefix,omitempty"` + // MacAddress contains the MAC address to set on the network interface + MacAddress string `json:"mac_address,omitempty"` + // Address contains the IPv4 and mask to set on the network interface Address string `json:"address,omitempty"` diff --git a/vendor/src/github.com/docker/libcontainer/network/veth.go b/vendor/src/github.com/docker/libcontainer/network/veth.go index c38fe3d2d5..e5185de7c7 100644 --- a/vendor/src/github.com/docker/libcontainer/network/veth.go +++ b/vendor/src/github.com/docker/libcontainer/network/veth.go @@ -5,6 +5,7 @@ package network import ( "fmt" + "github.com/docker/libcontainer/netlink" "github.com/docker/libcontainer/utils" ) @@ -60,6 +61,11 @@ func (v *Veth) Initialize(config *Network, networkState *NetworkState) error { if err := ChangeInterfaceName(vethChild, defaultDevice); err != nil { return fmt.Errorf("change %s to %s %s", vethChild, defaultDevice, err) } + if config.MacAddress != "" { + if err := SetInterfaceMac(defaultDevice, config.MacAddress); err != nil { + return fmt.Errorf("set %s mac %s", defaultDevice, err) + } + } if err := SetInterfaceIp(defaultDevice, config.Address); err != nil { return fmt.Errorf("set %s ip %s", defaultDevice, err) } @@ -91,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/vendor/src/github.com/docker/libcontainer/network/veth_test.go b/vendor/src/github.com/docker/libcontainer/network/veth_test.go new file mode 100644 index 0000000000..e09a6042c7 --- /dev/null +++ b/vendor/src/github.com/docker/libcontainer/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) + } +} diff --git a/vendor/src/github.com/docker/libcontainer/system/xattrs_linux.go b/vendor/src/github.com/docker/libcontainer/system/xattrs_linux.go index 00edb201b5..30f74dfb1b 100644 --- a/vendor/src/github.com/docker/libcontainer/system/xattrs_linux.go +++ b/vendor/src/github.com/docker/libcontainer/system/xattrs_linux.go @@ -5,8 +5,35 @@ import ( "unsafe" ) -// Returns a nil slice and nil error if the xattr is not set +var _zero uintptr + +// Returns the size of xattrs and nil error +// Requires path, takes allocated []byte or nil as last argument +func Llistxattr(path string, dest []byte) (size int, err error) { + pathBytes, err := syscall.BytePtrFromString(path) + if err != nil { + return -1, err + } + var newpathBytes unsafe.Pointer + if len(dest) > 0 { + newpathBytes = unsafe.Pointer(&dest[0]) + } else { + newpathBytes = unsafe.Pointer(&_zero) + } + + _size, _, errno := syscall.Syscall6(syscall.SYS_LLISTXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(newpathBytes), uintptr(len(dest)), 0, 0, 0) + size = int(_size) + if errno != 0 { + return -1, errno + } + + return size, nil +} + +// Returns a []byte slice if the xattr is set and nil otherwise +// Requires path and its attribute as arguments func Lgetxattr(path string, attr string) ([]byte, error) { + var sz int pathBytes, err := syscall.BytePtrFromString(path) if err != nil { return nil, err @@ -16,26 +43,39 @@ func Lgetxattr(path string, attr string) ([]byte, error) { return nil, err } - dest := make([]byte, 128) + // Start with a 128 length byte array + sz = 128 + dest := make([]byte, sz) destBytes := unsafe.Pointer(&dest[0]) - sz, _, errno := syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0) - if errno == syscall.ENODATA { - return nil, nil - } - if errno == syscall.ERANGE { + _sz, _, errno := syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0) + + switch { + case errno == syscall.ENODATA: + return nil, errno + case errno == syscall.ENOTSUP: + return nil, errno + case errno == syscall.ERANGE: + // 128 byte array might just not be good enough, + // A dummy buffer is used ``uintptr(0)`` to get real size + // of the xattrs on disk + _sz, _, errno = syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(unsafe.Pointer(nil)), uintptr(0), 0, 0) + sz = int(_sz) + if sz < 0 { + return nil, errno + } dest = make([]byte, sz) destBytes := unsafe.Pointer(&dest[0]) - sz, _, errno = syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0) - } - if errno != 0 { + _sz, _, errno = syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0) + if errno != 0 { + return nil, errno + } + case errno != 0: return nil, errno } - + sz = int(_sz) return dest[:sz], nil } -var _zero uintptr - func Lsetxattr(path string, attr string, data []byte, flags int) error { pathBytes, err := syscall.BytePtrFromString(path) if err != nil { diff --git a/vendor/src/github.com/docker/libcontainer/xattr/xattr.go b/vendor/src/github.com/docker/libcontainer/xattr/xattr.go new file mode 100644 index 0000000000..fc08d01fd9 --- /dev/null +++ b/vendor/src/github.com/docker/libcontainer/xattr/xattr.go @@ -0,0 +1,53 @@ +// +build linux + +package xattr + +import ( + "syscall" + + "github.com/docker/libcontainer/system" +) + +func XattrEnabled(path string) bool { + if Setxattr(path, "user.test", "") == syscall.ENOTSUP { + return false + } + return true +} + +func stringsfromByte(buf []byte) (result []string) { + offset := 0 + for index, b := range buf { + if b == 0 { + result = append(result, string(buf[offset:index])) + offset = index + 1 + } + } + return +} + +func Listxattr(path string) ([]string, error) { + size, err := system.Llistxattr(path, nil) + if err != nil { + return nil, err + } + buf := make([]byte, size) + read, err := system.Llistxattr(path, buf) + if err != nil { + return nil, err + } + names := stringsfromByte(buf[:read]) + return names, nil +} + +func Getxattr(path, attr string) (string, error) { + value, err := system.Lgetxattr(path, attr) + if err != nil { + return "", err + } + return string(value), nil +} + +func Setxattr(path, xattr, value string) error { + return system.Lsetxattr(path, xattr, []byte(value), 0) +} diff --git a/vendor/src/github.com/docker/libcontainer/xattr/xattr_test.go b/vendor/src/github.com/docker/libcontainer/xattr/xattr_test.go new file mode 100644 index 0000000000..d818c691d4 --- /dev/null +++ b/vendor/src/github.com/docker/libcontainer/xattr/xattr_test.go @@ -0,0 +1,77 @@ +// +build linux + +package xattr_test + +import ( + "os" + "testing" + + "github.com/docker/libcontainer/xattr" +) + +func testXattr(t *testing.T) { + tmp := "xattr_test" + out, err := os.OpenFile(tmp, os.O_WRONLY, 0) + if err != nil { + t.Fatal("failed") + } + attr := "user.test" + out.Close() + + if !xattr.XattrEnabled(tmp) { + t.Log("Disabled") + t.Fatal("failed") + } + t.Log("Success") + + err = xattr.Setxattr(tmp, attr, "test") + if err != nil { + t.Fatal("failed") + } + + var value string + value, err = xattr.Getxattr(tmp, attr) + if err != nil { + t.Fatal("failed") + } + if value != "test" { + t.Fatal("failed") + } + t.Log("Success") + + var names []string + names, err = xattr.Listxattr(tmp) + if err != nil { + t.Fatal("failed") + } + + var found int + for _, name := range names { + if name == attr { + found = 1 + } + } + // Listxattr doesn't return trusted.* and system.* namespace + // attrs when run in unprevileged mode. + if found != 1 { + t.Fatal("failed") + } + t.Log("Success") + + big := "0000000000000000000000000000000000000000000000000000000000000000000008c6419ad822dfe29283fb3ac98dcc5908810cb31f4cfe690040c42c144b7492eicompslf20dxmlpgz" + // Test for long xattrs larger than 128 bytes + err = xattr.Setxattr(tmp, attr, big) + if err != nil { + t.Fatal("failed to add long value") + } + value, err = xattr.Getxattr(tmp, attr) + if err != nil { + t.Fatal("failed to get long value") + } + t.Log("Success") + + if value != big { + t.Fatal("failed, value doesn't match") + } + t.Log("Success") +}