diff --git a/drivers/bridge/bridge.go b/drivers/bridge/bridge.go index 1255da4..144cf87 100644 --- a/drivers/bridge/bridge.go +++ b/drivers/bridge/bridge.go @@ -7,17 +7,19 @@ import ( "strings" "sync" - "github.com/docker/libcontainer/utils" "github.com/docker/libnetwork/driverapi" "github.com/docker/libnetwork/ipallocator" + "github.com/docker/libnetwork/netutils" "github.com/docker/libnetwork/pkg/options" "github.com/docker/libnetwork/portmapper" "github.com/vishvananda/netlink" ) const ( - networkType = "simplebridge" - vethPrefix = "veth" + networkType = "simplebridge" + vethPrefix = "veth" + vethLen = 7 + containerVeth = "eth0" ) var ( @@ -292,7 +294,7 @@ func (d *driver) CreateEndpoint(nid, eid driverapi.UUID, sboxKey string, config intf := &driverapi.Interface{} intf.SrcName = name2 - intf.DstName = "eth0" + intf.DstName = containerVeth intf.Address = ipv4Addr sinfo.Gateway = n.bridge.bridgeIPv4.IP if n.bridge.Config.EnableIPv6 { @@ -364,9 +366,12 @@ func (d *driver) DeleteEndpoint(nid, eid driverapi.UUID) error { 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) { - 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 { continue } diff --git a/netutils/utils.go b/netutils/utils.go index ce1c619..eff88df 100644 --- a/netutils/utils.go +++ b/netutils/utils.go @@ -1,12 +1,13 @@ // Network utility functions. -// Imported unchanged from Docker package netutils import ( + "crypto/rand" + "encoding/hex" "errors" "fmt" - "math/rand" + "io" "net" "github.com/vishvananda/netlink" @@ -115,13 +116,32 @@ func GetIfaceAddr(name string) (net.Addr, []net.Addr, error) { 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 { 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 } + +// 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 +} diff --git a/netutils/utils_test.go b/netutils/utils_test.go index 96faa08..78de626 100644 --- a/netutils/utils_test.go +++ b/netutils/utils_test.go @@ -1,6 +1,7 @@ package netutils import ( + "bytes" "net" "testing" @@ -174,3 +175,37 @@ func TestNetworkRange(t *testing.T) { 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) + } +}