Browse code

Merge pull request #8367 from crosbymichael/update-libcontainer-sep9

Update libconatiner to b3570267c7b7995d5d618974d8f

Victor Vieux authored on 2014/10/03 07:41:06
Showing 11 changed files
... ...
@@ -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
... ...
@@ -328,7 +328,7 @@ func TestCreateBridgeWithMac(t *testing.T) {
328 328
 	}
329 329
 }
330 330
 
331
-func TestSetMACAddress(t *testing.T) {
331
+func TestSetMacAddress(t *testing.T) {
332 332
 	if testing.Short() {
333 333
 		return
334 334
 	}
... ...
@@ -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
+}