Procházet zdrojové kódy

Name/Mac generation and libcontainer dep removal

- Modified Mac address generation to match current standard
- Moved GenerateRandomName from libcontainer and removed the dependancy.
- Reduced entropy loop to 3 attempts.

Signed-off-by: Brent Salisbury <brent.salisbury@docker.com>
Brent Salisbury před 10 roky
rodič
revize
d8f88b2afb

+ 11 - 6
libnetwork/drivers/bridge/bridge.go

@@ -7,17 +7,19 @@ import (
 	"strings"
 	"strings"
 	"sync"
 	"sync"
 
 
-	"github.com/docker/libcontainer/utils"
 	"github.com/docker/libnetwork/driverapi"
 	"github.com/docker/libnetwork/driverapi"
 	"github.com/docker/libnetwork/ipallocator"
 	"github.com/docker/libnetwork/ipallocator"
+	"github.com/docker/libnetwork/netutils"
 	"github.com/docker/libnetwork/pkg/options"
 	"github.com/docker/libnetwork/pkg/options"
 	"github.com/docker/libnetwork/portmapper"
 	"github.com/docker/libnetwork/portmapper"
 	"github.com/vishvananda/netlink"
 	"github.com/vishvananda/netlink"
 )
 )
 
 
 const (
 const (
-	networkType = "simplebridge"
-	vethPrefix  = "veth"
+	networkType   = "simplebridge"
+	vethPrefix    = "veth"
+	vethLen       = 7
+	containerVeth = "eth0"
 )
 )
 
 
 var (
 var (
@@ -292,7 +294,7 @@ func (d *driver) CreateEndpoint(nid, eid driverapi.UUID, sboxKey string, config
 
 
 	intf := &driverapi.Interface{}
 	intf := &driverapi.Interface{}
 	intf.SrcName = name2
 	intf.SrcName = name2
-	intf.DstName = "eth0"
+	intf.DstName = containerVeth
 	intf.Address = ipv4Addr
 	intf.Address = ipv4Addr
 	sinfo.Gateway = n.bridge.bridgeIPv4.IP
 	sinfo.Gateway = n.bridge.bridgeIPv4.IP
 	if n.bridge.Config.EnableIPv6 {
 	if n.bridge.Config.EnableIPv6 {
@@ -364,9 +366,12 @@ func (d *driver) DeleteEndpoint(nid, eid driverapi.UUID) error {
 	return nil
 	return nil
 }
 }
 
 
+// Generates a name to be used for a virtual ethernet
+// interface. The name is constructed by 'veth' appended
+// by a randomly generated hex value. (example: veth0f60e2c)
 func generateIfaceName() (string, error) {
 func generateIfaceName() (string, error) {
-	for i := 0; i < 10; i++ {
-		name, err := utils.GenerateRandomName("veth", 7)
+	for i := 0; i < 3; i++ {
+		name, err := netutils.GenerateRandomName(vethPrefix, vethLen)
 		if err != nil {
 		if err != nil {
 			continue
 			continue
 		}
 		}

+ 27 - 7
libnetwork/netutils/utils.go

@@ -1,12 +1,13 @@
 // Network utility functions.
 // Network utility functions.
-// Imported unchanged from Docker
 
 
 package netutils
 package netutils
 
 
 import (
 import (
+	"crypto/rand"
+	"encoding/hex"
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
-	"math/rand"
+	"io"
 	"net"
 	"net"
 
 
 	"github.com/vishvananda/netlink"
 	"github.com/vishvananda/netlink"
@@ -115,13 +116,32 @@ func GetIfaceAddr(name string) (net.Addr, []net.Addr, error) {
 	return addrs4[0], addrs6, nil
 	return addrs4[0], addrs6, nil
 }
 }
 
 
-// GenerateRandomMAC returns a random MAC address
+// GenerateRandomMAC returns a new 6-byte(48-bit) hardware address (MAC)
 func GenerateRandomMAC() net.HardwareAddr {
 func GenerateRandomMAC() net.HardwareAddr {
 	hw := make(net.HardwareAddr, 6)
 	hw := make(net.HardwareAddr, 6)
-	for i := 0; i < 6; i++ {
-		hw[i] = byte(rand.Intn(255))
+	// The first byte of the MAC address has to comply with these rules:
+	// 1. Unicast: Set the least-significant bit to 0.
+	// 2. Address is locally administered: Set the second-least-significant bit (U/L) to 1.
+	// 3. As "small" as possible: The veth address has to be "smaller" than the bridge address.
+	hw[0] = 0x02
+	// The first 24 bits of the MAC represent the Organizationally Unique Identifier (OUI).
+	// Since this address is locally administered, we can do whatever we want as long as
+	// it doesn't conflict with other addresses.
+	hw[1] = 0x42
+	// Randomly generate the remaining 4 bytes (2^32)
+	_, err := rand.Read(hw[2:])
+	if err != nil {
+		return nil
 	}
 	}
-	hw[0] &^= 0x1 // clear multicast bit
-	hw[0] |= 0x2  // set local assignment bit (IEEE802)
 	return hw
 	return hw
 }
 }
+
+// GenerateRandomName returns a new name joined with a prefix.  This size
+// specified is used to truncate the randomly generated value
+func GenerateRandomName(prefix string, size int) (string, error) {
+	id := make([]byte, 32)
+	if _, err := io.ReadFull(rand.Reader, id); err != nil {
+		return "", err
+	}
+	return prefix + hex.EncodeToString(id)[:size], nil
+}

+ 35 - 0
libnetwork/netutils/utils_test.go

@@ -1,6 +1,7 @@
 package netutils
 package netutils
 
 
 import (
 import (
+	"bytes"
 	"net"
 	"net"
 	"testing"
 	"testing"
 
 
@@ -174,3 +175,37 @@ func TestNetworkRange(t *testing.T) {
 		t.Error(last.String())
 		t.Error(last.String())
 	}
 	}
 }
 }
+
+// Test veth name generation "veth"+rand (e.g.veth0f60e2c)
+func TestGenerateRandomName(t *testing.T) {
+	name1, err := GenerateRandomName("veth", 7)
+	if err != nil {
+		t.Fatal(err)
+	}
+	// veth plus generated append equals a len of 11
+	if len(name1) != 11 {
+		t.Fatalf("Expected 11 characters, instead received %d characters", len(name1))
+	}
+	name2, err := GenerateRandomName("veth", 7)
+	if err != nil {
+		t.Fatal(err)
+	}
+	// Fail if the random generated names equal one another
+	if name1 == name2 {
+		t.Fatalf("Expected differing values but received %s and %s", name1, name2)
+	}
+}
+
+// Test mac generation.
+func TestUtilGenerateRandomMAC(t *testing.T) {
+	mac1 := GenerateRandomMAC()
+	mac2 := GenerateRandomMAC()
+	// ensure bytes are unique
+	if bytes.Equal(mac1, mac2) {
+		t.Fatalf("mac1 %s should not equal mac2 %s", mac1, mac2)
+	}
+	// existing tests check string functionality so keeping the pattern
+	if mac1.String() == mac2.String() {
+		t.Fatalf("mac1 %s should not equal mac2 %s", mac1, mac2)
+	}
+}