Update libconatiner to b3570267c7b7995d5d618974d8f
| ... | ... |
@@ -64,7 +64,7 @@ if [ "$1" = '--go' ]; then |
| 64 | 64 |
mv tmp-tar src/code.google.com/p/go/src/pkg/archive/tar |
| 65 | 65 |
fi |
| 66 | 66 |
|
| 67 |
-clone git github.com/docker/libcontainer c744f6470e37be5ce1f1ae09b842c15c1bee120d |
|
| 67 |
+clone git github.com/docker/libcontainer b3570267c7b7995d5d618974d8f7be4fe5ab076a |
|
| 68 | 68 |
# see src/github.com/docker/libcontainer/update-vendor.sh which is the "source of truth" for libcontainer deps (just like this file) |
| 69 | 69 |
rm -rf src/github.com/docker/libcontainer/vendor |
| 70 | 70 |
eval "$(grep '^clone ' src/github.com/docker/libcontainer/update-vendor.sh | grep -v 'github.com/codegangsta/cli')" |
| ... | ... |
@@ -11,8 +11,9 @@ import ( |
| 11 | 11 |
) |
| 12 | 12 |
|
| 13 | 13 |
var ( |
| 14 |
- ErrWrongSockType = errors.New("Wrong socket type")
|
|
| 15 |
- ErrShortResponse = errors.New("Got short response from netlink")
|
|
| 14 |
+ ErrWrongSockType = errors.New("Wrong socket type")
|
|
| 15 |
+ ErrShortResponse = errors.New("Got short response from netlink")
|
|
| 16 |
+ ErrInterfaceExists = errors.New("Network interface already exists")
|
|
| 16 | 17 |
) |
| 17 | 18 |
|
| 18 | 19 |
// A Route is a subnet associated with the interface to reach it. |
| ... | ... |
@@ -6,6 +6,7 @@ import ( |
| 6 | 6 |
"io" |
| 7 | 7 |
"math/rand" |
| 8 | 8 |
"net" |
| 9 |
+ "os" |
|
| 9 | 10 |
"sync/atomic" |
| 10 | 11 |
"syscall" |
| 11 | 12 |
"unsafe" |
| ... | ... |
@@ -708,7 +709,16 @@ func NetworkCreateVethPair(name1, name2 string) error {
|
| 708 | 708 |
if err := s.Send(wb); err != nil {
|
| 709 | 709 |
return err |
| 710 | 710 |
} |
| 711 |
- return s.HandleAck(wb.Seq) |
|
| 711 |
+ |
|
| 712 |
+ if err := s.HandleAck(wb.Seq); err != nil {
|
|
| 713 |
+ if os.IsExist(err) {
|
|
| 714 |
+ return ErrInterfaceExists |
|
| 715 |
+ } |
|
| 716 |
+ |
|
| 717 |
+ return err |
|
| 718 |
+ } |
|
| 719 |
+ |
|
| 720 |
+ return nil |
|
| 712 | 721 |
} |
| 713 | 722 |
|
| 714 | 723 |
// Add a new VLAN interface with masterDev as its upper device |
| ... | ... |
@@ -68,6 +68,14 @@ func SetDefaultGateway(ip, ifaceName string) error {
|
| 68 | 68 |
return netlink.AddDefaultGw(ip, ifaceName) |
| 69 | 69 |
} |
| 70 | 70 |
|
| 71 |
+func SetInterfaceMac(name string, macaddr string) error {
|
|
| 72 |
+ iface, err := net.InterfaceByName(name) |
|
| 73 |
+ if err != nil {
|
|
| 74 |
+ return err |
|
| 75 |
+ } |
|
| 76 |
+ return netlink.NetworkSetMacAddress(iface, macaddr) |
|
| 77 |
+} |
|
| 78 |
+ |
|
| 71 | 79 |
func SetInterfaceIp(name string, rawIp string) error {
|
| 72 | 80 |
iface, err := net.InterfaceByName(name) |
| 73 | 81 |
if err != nil {
|
| ... | ... |
@@ -17,6 +17,9 @@ type Network struct {
|
| 17 | 17 |
// Prefix for the veth interfaces. |
| 18 | 18 |
VethPrefix string `json:"veth_prefix,omitempty"` |
| 19 | 19 |
|
| 20 |
+ // MacAddress contains the MAC address to set on the network interface |
|
| 21 |
+ MacAddress string `json:"mac_address,omitempty"` |
|
| 22 |
+ |
|
| 20 | 23 |
// Address contains the IPv4 and mask to set on the network interface |
| 21 | 24 |
Address string `json:"address,omitempty"` |
| 22 | 25 |
|
| ... | ... |
@@ -5,6 +5,7 @@ package network |
| 5 | 5 |
import ( |
| 6 | 6 |
"fmt" |
| 7 | 7 |
|
| 8 |
+ "github.com/docker/libcontainer/netlink" |
|
| 8 | 9 |
"github.com/docker/libcontainer/utils" |
| 9 | 10 |
) |
| 10 | 11 |
|
| ... | ... |
@@ -60,6 +61,11 @@ func (v *Veth) Initialize(config *Network, networkState *NetworkState) error {
|
| 60 | 60 |
if err := ChangeInterfaceName(vethChild, defaultDevice); err != nil {
|
| 61 | 61 |
return fmt.Errorf("change %s to %s %s", vethChild, defaultDevice, err)
|
| 62 | 62 |
} |
| 63 |
+ if config.MacAddress != "" {
|
|
| 64 |
+ if err := SetInterfaceMac(defaultDevice, config.MacAddress); err != nil {
|
|
| 65 |
+ return fmt.Errorf("set %s mac %s", defaultDevice, err)
|
|
| 66 |
+ } |
|
| 67 |
+ } |
|
| 63 | 68 |
if err := SetInterfaceIp(defaultDevice, config.Address); err != nil {
|
| 64 | 69 |
return fmt.Errorf("set %s ip %s", defaultDevice, err)
|
| 65 | 70 |
} |
| ... | ... |
@@ -91,16 +97,25 @@ func (v *Veth) Initialize(config *Network, networkState *NetworkState) error {
|
| 91 | 91 |
// createVethPair will automatically generage two random names for |
| 92 | 92 |
// the veth pair and ensure that they have been created |
| 93 | 93 |
func createVethPair(prefix string) (name1 string, name2 string, err error) {
|
| 94 |
- name1, err = utils.GenerateRandomName(prefix, 4) |
|
| 95 |
- if err != nil {
|
|
| 96 |
- return |
|
| 97 |
- } |
|
| 98 |
- name2, err = utils.GenerateRandomName(prefix, 4) |
|
| 99 |
- if err != nil {
|
|
| 100 |
- return |
|
| 101 |
- } |
|
| 102 |
- if err = CreateVethPair(name1, name2); err != nil {
|
|
| 103 |
- return |
|
| 94 |
+ for i := 0; i < 10; i++ {
|
|
| 95 |
+ if name1, err = utils.GenerateRandomName(prefix, 7); err != nil {
|
|
| 96 |
+ return |
|
| 97 |
+ } |
|
| 98 |
+ |
|
| 99 |
+ if name2, err = utils.GenerateRandomName(prefix, 7); err != nil {
|
|
| 100 |
+ return |
|
| 101 |
+ } |
|
| 102 |
+ |
|
| 103 |
+ if err = CreateVethPair(name1, name2); err != nil {
|
|
| 104 |
+ if err == netlink.ErrInterfaceExists {
|
|
| 105 |
+ continue |
|
| 106 |
+ } |
|
| 107 |
+ |
|
| 108 |
+ return |
|
| 109 |
+ } |
|
| 110 |
+ |
|
| 111 |
+ break |
|
| 104 | 112 |
} |
| 113 |
+ |
|
| 105 | 114 |
return |
| 106 | 115 |
} |
| 107 | 116 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,53 @@ |
| 0 |
+// +build linux |
|
| 1 |
+ |
|
| 2 |
+package network |
|
| 3 |
+ |
|
| 4 |
+import ( |
|
| 5 |
+ "testing" |
|
| 6 |
+ |
|
| 7 |
+ "github.com/docker/libcontainer/netlink" |
|
| 8 |
+) |
|
| 9 |
+ |
|
| 10 |
+func TestGenerateVethNames(t *testing.T) {
|
|
| 11 |
+ if testing.Short() {
|
|
| 12 |
+ return |
|
| 13 |
+ } |
|
| 14 |
+ |
|
| 15 |
+ prefix := "veth" |
|
| 16 |
+ |
|
| 17 |
+ name1, name2, err := createVethPair(prefix) |
|
| 18 |
+ if err != nil {
|
|
| 19 |
+ t.Fatal(err) |
|
| 20 |
+ } |
|
| 21 |
+ |
|
| 22 |
+ if name1 == "" {
|
|
| 23 |
+ t.Fatal("name1 should not be empty")
|
|
| 24 |
+ } |
|
| 25 |
+ |
|
| 26 |
+ if name2 == "" {
|
|
| 27 |
+ t.Fatal("name2 should not be empty")
|
|
| 28 |
+ } |
|
| 29 |
+} |
|
| 30 |
+ |
|
| 31 |
+func TestCreateDuplicateVethPair(t *testing.T) {
|
|
| 32 |
+ if testing.Short() {
|
|
| 33 |
+ return |
|
| 34 |
+ } |
|
| 35 |
+ |
|
| 36 |
+ prefix := "veth" |
|
| 37 |
+ |
|
| 38 |
+ name1, name2, err := createVethPair(prefix) |
|
| 39 |
+ if err != nil {
|
|
| 40 |
+ t.Fatal(err) |
|
| 41 |
+ } |
|
| 42 |
+ |
|
| 43 |
+ // retry to create the name interfaces and make sure that we get the correct error |
|
| 44 |
+ err = CreateVethPair(name1, name2) |
|
| 45 |
+ if err == nil {
|
|
| 46 |
+ t.Fatal("expected error to not be nil with duplicate interface")
|
|
| 47 |
+ } |
|
| 48 |
+ |
|
| 49 |
+ if err != netlink.ErrInterfaceExists {
|
|
| 50 |
+ t.Fatalf("expected error to be ErrInterfaceExists but received %q", err)
|
|
| 51 |
+ } |
|
| 52 |
+} |
| ... | ... |
@@ -5,8 +5,35 @@ import ( |
| 5 | 5 |
"unsafe" |
| 6 | 6 |
) |
| 7 | 7 |
|
| 8 |
-// Returns a nil slice and nil error if the xattr is not set |
|
| 8 |
+var _zero uintptr |
|
| 9 |
+ |
|
| 10 |
+// Returns the size of xattrs and nil error |
|
| 11 |
+// Requires path, takes allocated []byte or nil as last argument |
|
| 12 |
+func Llistxattr(path string, dest []byte) (size int, err error) {
|
|
| 13 |
+ pathBytes, err := syscall.BytePtrFromString(path) |
|
| 14 |
+ if err != nil {
|
|
| 15 |
+ return -1, err |
|
| 16 |
+ } |
|
| 17 |
+ var newpathBytes unsafe.Pointer |
|
| 18 |
+ if len(dest) > 0 {
|
|
| 19 |
+ newpathBytes = unsafe.Pointer(&dest[0]) |
|
| 20 |
+ } else {
|
|
| 21 |
+ newpathBytes = unsafe.Pointer(&_zero) |
|
| 22 |
+ } |
|
| 23 |
+ |
|
| 24 |
+ _size, _, errno := syscall.Syscall6(syscall.SYS_LLISTXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(newpathBytes), uintptr(len(dest)), 0, 0, 0) |
|
| 25 |
+ size = int(_size) |
|
| 26 |
+ if errno != 0 {
|
|
| 27 |
+ return -1, errno |
|
| 28 |
+ } |
|
| 29 |
+ |
|
| 30 |
+ return size, nil |
|
| 31 |
+} |
|
| 32 |
+ |
|
| 33 |
+// Returns a []byte slice if the xattr is set and nil otherwise |
|
| 34 |
+// Requires path and its attribute as arguments |
|
| 9 | 35 |
func Lgetxattr(path string, attr string) ([]byte, error) {
|
| 36 |
+ var sz int |
|
| 10 | 37 |
pathBytes, err := syscall.BytePtrFromString(path) |
| 11 | 38 |
if err != nil {
|
| 12 | 39 |
return nil, err |
| ... | ... |
@@ -16,26 +43,39 @@ func Lgetxattr(path string, attr string) ([]byte, error) {
|
| 16 | 16 |
return nil, err |
| 17 | 17 |
} |
| 18 | 18 |
|
| 19 |
- dest := make([]byte, 128) |
|
| 19 |
+ // Start with a 128 length byte array |
|
| 20 |
+ sz = 128 |
|
| 21 |
+ dest := make([]byte, sz) |
|
| 20 | 22 |
destBytes := unsafe.Pointer(&dest[0]) |
| 21 |
- sz, _, errno := syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0) |
|
| 22 |
- if errno == syscall.ENODATA {
|
|
| 23 |
- return nil, nil |
|
| 24 |
- } |
|
| 25 |
- if errno == syscall.ERANGE {
|
|
| 23 |
+ _sz, _, errno := syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0) |
|
| 24 |
+ |
|
| 25 |
+ switch {
|
|
| 26 |
+ case errno == syscall.ENODATA: |
|
| 27 |
+ return nil, errno |
|
| 28 |
+ case errno == syscall.ENOTSUP: |
|
| 29 |
+ return nil, errno |
|
| 30 |
+ case errno == syscall.ERANGE: |
|
| 31 |
+ // 128 byte array might just not be good enough, |
|
| 32 |
+ // A dummy buffer is used ``uintptr(0)`` to get real size |
|
| 33 |
+ // of the xattrs on disk |
|
| 34 |
+ _sz, _, errno = syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(unsafe.Pointer(nil)), uintptr(0), 0, 0) |
|
| 35 |
+ sz = int(_sz) |
|
| 36 |
+ if sz < 0 {
|
|
| 37 |
+ return nil, errno |
|
| 38 |
+ } |
|
| 26 | 39 |
dest = make([]byte, sz) |
| 27 | 40 |
destBytes := unsafe.Pointer(&dest[0]) |
| 28 |
- sz, _, errno = syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0) |
|
| 29 |
- } |
|
| 30 |
- if errno != 0 {
|
|
| 41 |
+ _sz, _, errno = syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0) |
|
| 42 |
+ if errno != 0 {
|
|
| 43 |
+ return nil, errno |
|
| 44 |
+ } |
|
| 45 |
+ case errno != 0: |
|
| 31 | 46 |
return nil, errno |
| 32 | 47 |
} |
| 33 |
- |
|
| 48 |
+ sz = int(_sz) |
|
| 34 | 49 |
return dest[:sz], nil |
| 35 | 50 |
} |
| 36 | 51 |
|
| 37 |
-var _zero uintptr |
|
| 38 |
- |
|
| 39 | 52 |
func Lsetxattr(path string, attr string, data []byte, flags int) error {
|
| 40 | 53 |
pathBytes, err := syscall.BytePtrFromString(path) |
| 41 | 54 |
if err != nil {
|
| 42 | 55 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,53 @@ |
| 0 |
+// +build linux |
|
| 1 |
+ |
|
| 2 |
+package xattr |
|
| 3 |
+ |
|
| 4 |
+import ( |
|
| 5 |
+ "syscall" |
|
| 6 |
+ |
|
| 7 |
+ "github.com/docker/libcontainer/system" |
|
| 8 |
+) |
|
| 9 |
+ |
|
| 10 |
+func XattrEnabled(path string) bool {
|
|
| 11 |
+ if Setxattr(path, "user.test", "") == syscall.ENOTSUP {
|
|
| 12 |
+ return false |
|
| 13 |
+ } |
|
| 14 |
+ return true |
|
| 15 |
+} |
|
| 16 |
+ |
|
| 17 |
+func stringsfromByte(buf []byte) (result []string) {
|
|
| 18 |
+ offset := 0 |
|
| 19 |
+ for index, b := range buf {
|
|
| 20 |
+ if b == 0 {
|
|
| 21 |
+ result = append(result, string(buf[offset:index])) |
|
| 22 |
+ offset = index + 1 |
|
| 23 |
+ } |
|
| 24 |
+ } |
|
| 25 |
+ return |
|
| 26 |
+} |
|
| 27 |
+ |
|
| 28 |
+func Listxattr(path string) ([]string, error) {
|
|
| 29 |
+ size, err := system.Llistxattr(path, nil) |
|
| 30 |
+ if err != nil {
|
|
| 31 |
+ return nil, err |
|
| 32 |
+ } |
|
| 33 |
+ buf := make([]byte, size) |
|
| 34 |
+ read, err := system.Llistxattr(path, buf) |
|
| 35 |
+ if err != nil {
|
|
| 36 |
+ return nil, err |
|
| 37 |
+ } |
|
| 38 |
+ names := stringsfromByte(buf[:read]) |
|
| 39 |
+ return names, nil |
|
| 40 |
+} |
|
| 41 |
+ |
|
| 42 |
+func Getxattr(path, attr string) (string, error) {
|
|
| 43 |
+ value, err := system.Lgetxattr(path, attr) |
|
| 44 |
+ if err != nil {
|
|
| 45 |
+ return "", err |
|
| 46 |
+ } |
|
| 47 |
+ return string(value), nil |
|
| 48 |
+} |
|
| 49 |
+ |
|
| 50 |
+func Setxattr(path, xattr, value string) error {
|
|
| 51 |
+ return system.Lsetxattr(path, xattr, []byte(value), 0) |
|
| 52 |
+} |
| 0 | 53 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,77 @@ |
| 0 |
+// +build linux |
|
| 1 |
+ |
|
| 2 |
+package xattr_test |
|
| 3 |
+ |
|
| 4 |
+import ( |
|
| 5 |
+ "os" |
|
| 6 |
+ "testing" |
|
| 7 |
+ |
|
| 8 |
+ "github.com/docker/libcontainer/xattr" |
|
| 9 |
+) |
|
| 10 |
+ |
|
| 11 |
+func testXattr(t *testing.T) {
|
|
| 12 |
+ tmp := "xattr_test" |
|
| 13 |
+ out, err := os.OpenFile(tmp, os.O_WRONLY, 0) |
|
| 14 |
+ if err != nil {
|
|
| 15 |
+ t.Fatal("failed")
|
|
| 16 |
+ } |
|
| 17 |
+ attr := "user.test" |
|
| 18 |
+ out.Close() |
|
| 19 |
+ |
|
| 20 |
+ if !xattr.XattrEnabled(tmp) {
|
|
| 21 |
+ t.Log("Disabled")
|
|
| 22 |
+ t.Fatal("failed")
|
|
| 23 |
+ } |
|
| 24 |
+ t.Log("Success")
|
|
| 25 |
+ |
|
| 26 |
+ err = xattr.Setxattr(tmp, attr, "test") |
|
| 27 |
+ if err != nil {
|
|
| 28 |
+ t.Fatal("failed")
|
|
| 29 |
+ } |
|
| 30 |
+ |
|
| 31 |
+ var value string |
|
| 32 |
+ value, err = xattr.Getxattr(tmp, attr) |
|
| 33 |
+ if err != nil {
|
|
| 34 |
+ t.Fatal("failed")
|
|
| 35 |
+ } |
|
| 36 |
+ if value != "test" {
|
|
| 37 |
+ t.Fatal("failed")
|
|
| 38 |
+ } |
|
| 39 |
+ t.Log("Success")
|
|
| 40 |
+ |
|
| 41 |
+ var names []string |
|
| 42 |
+ names, err = xattr.Listxattr(tmp) |
|
| 43 |
+ if err != nil {
|
|
| 44 |
+ t.Fatal("failed")
|
|
| 45 |
+ } |
|
| 46 |
+ |
|
| 47 |
+ var found int |
|
| 48 |
+ for _, name := range names {
|
|
| 49 |
+ if name == attr {
|
|
| 50 |
+ found = 1 |
|
| 51 |
+ } |
|
| 52 |
+ } |
|
| 53 |
+ // Listxattr doesn't return trusted.* and system.* namespace |
|
| 54 |
+ // attrs when run in unprevileged mode. |
|
| 55 |
+ if found != 1 {
|
|
| 56 |
+ t.Fatal("failed")
|
|
| 57 |
+ } |
|
| 58 |
+ t.Log("Success")
|
|
| 59 |
+ |
|
| 60 |
+ big := "0000000000000000000000000000000000000000000000000000000000000000000008c6419ad822dfe29283fb3ac98dcc5908810cb31f4cfe690040c42c144b7492eicompslf20dxmlpgz" |
|
| 61 |
+ // Test for long xattrs larger than 128 bytes |
|
| 62 |
+ err = xattr.Setxattr(tmp, attr, big) |
|
| 63 |
+ if err != nil {
|
|
| 64 |
+ t.Fatal("failed to add long value")
|
|
| 65 |
+ } |
|
| 66 |
+ value, err = xattr.Getxattr(tmp, attr) |
|
| 67 |
+ if err != nil {
|
|
| 68 |
+ t.Fatal("failed to get long value")
|
|
| 69 |
+ } |
|
| 70 |
+ t.Log("Success")
|
|
| 71 |
+ |
|
| 72 |
+ if value != big {
|
|
| 73 |
+ t.Fatal("failed, value doesn't match")
|
|
| 74 |
+ } |
|
| 75 |
+ t.Log("Success")
|
|
| 76 |
+} |