Browse code

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 authored on 2015/04/14 13:12:40
Showing 3 changed files
... ...
@@ -7,17 +7,19 @@ import (
7 7
 	"strings"
8 8
 	"sync"
9 9
 
10
-	"github.com/docker/libcontainer/utils"
11 10
 	"github.com/docker/libnetwork/driverapi"
12 11
 	"github.com/docker/libnetwork/ipallocator"
12
+	"github.com/docker/libnetwork/netutils"
13 13
 	"github.com/docker/libnetwork/pkg/options"
14 14
 	"github.com/docker/libnetwork/portmapper"
15 15
 	"github.com/vishvananda/netlink"
16 16
 )
17 17
 
18 18
 const (
19
-	networkType = "simplebridge"
20
-	vethPrefix  = "veth"
19
+	networkType   = "simplebridge"
20
+	vethPrefix    = "veth"
21
+	vethLen       = 7
22
+	containerVeth = "eth0"
21 23
 )
22 24
 
23 25
 var (
... ...
@@ -292,7 +294,7 @@ func (d *driver) CreateEndpoint(nid, eid driverapi.UUID, sboxKey string, config
292 292
 
293 293
 	intf := &driverapi.Interface{}
294 294
 	intf.SrcName = name2
295
-	intf.DstName = "eth0"
295
+	intf.DstName = containerVeth
296 296
 	intf.Address = ipv4Addr
297 297
 	sinfo.Gateway = n.bridge.bridgeIPv4.IP
298 298
 	if n.bridge.Config.EnableIPv6 {
... ...
@@ -364,9 +366,12 @@ func (d *driver) DeleteEndpoint(nid, eid driverapi.UUID) error {
364 364
 	return nil
365 365
 }
366 366
 
367
+// Generates a name to be used for a virtual ethernet
368
+// interface. The name is constructed by 'veth' appended
369
+// by a randomly generated hex value. (example: veth0f60e2c)
367 370
 func generateIfaceName() (string, error) {
368
-	for i := 0; i < 10; i++ {
369
-		name, err := utils.GenerateRandomName("veth", 7)
371
+	for i := 0; i < 3; i++ {
372
+		name, err := netutils.GenerateRandomName(vethPrefix, vethLen)
370 373
 		if err != nil {
371 374
 			continue
372 375
 		}
... ...
@@ -1,12 +1,13 @@
1 1
 // Network utility functions.
2
-// Imported unchanged from Docker
3 2
 
4 3
 package netutils
5 4
 
6 5
 import (
6
+	"crypto/rand"
7
+	"encoding/hex"
7 8
 	"errors"
8 9
 	"fmt"
9
-	"math/rand"
10
+	"io"
10 11
 	"net"
11 12
 
12 13
 	"github.com/vishvananda/netlink"
... ...
@@ -115,13 +116,32 @@ func GetIfaceAddr(name string) (net.Addr, []net.Addr, error) {
115 115
 	return addrs4[0], addrs6, nil
116 116
 }
117 117
 
118
-// GenerateRandomMAC returns a random MAC address
118
+// GenerateRandomMAC returns a new 6-byte(48-bit) hardware address (MAC)
119 119
 func GenerateRandomMAC() net.HardwareAddr {
120 120
 	hw := make(net.HardwareAddr, 6)
121
-	for i := 0; i < 6; i++ {
122
-		hw[i] = byte(rand.Intn(255))
121
+	// The first byte of the MAC address has to comply with these rules:
122
+	// 1. Unicast: Set the least-significant bit to 0.
123
+	// 2. Address is locally administered: Set the second-least-significant bit (U/L) to 1.
124
+	// 3. As "small" as possible: The veth address has to be "smaller" than the bridge address.
125
+	hw[0] = 0x02
126
+	// The first 24 bits of the MAC represent the Organizationally Unique Identifier (OUI).
127
+	// Since this address is locally administered, we can do whatever we want as long as
128
+	// it doesn't conflict with other addresses.
129
+	hw[1] = 0x42
130
+	// Randomly generate the remaining 4 bytes (2^32)
131
+	_, err := rand.Read(hw[2:])
132
+	if err != nil {
133
+		return nil
123 134
 	}
124
-	hw[0] &^= 0x1 // clear multicast bit
125
-	hw[0] |= 0x2  // set local assignment bit (IEEE802)
126 135
 	return hw
127 136
 }
137
+
138
+// GenerateRandomName returns a new name joined with a prefix.  This size
139
+// specified is used to truncate the randomly generated value
140
+func GenerateRandomName(prefix string, size int) (string, error) {
141
+	id := make([]byte, 32)
142
+	if _, err := io.ReadFull(rand.Reader, id); err != nil {
143
+		return "", err
144
+	}
145
+	return prefix + hex.EncodeToString(id)[:size], nil
146
+}
... ...
@@ -1,6 +1,7 @@
1 1
 package netutils
2 2
 
3 3
 import (
4
+	"bytes"
4 5
 	"net"
5 6
 	"testing"
6 7
 
... ...
@@ -174,3 +175,37 @@ func TestNetworkRange(t *testing.T) {
174 174
 		t.Error(last.String())
175 175
 	}
176 176
 }
177
+
178
+// Test veth name generation "veth"+rand (e.g.veth0f60e2c)
179
+func TestGenerateRandomName(t *testing.T) {
180
+	name1, err := GenerateRandomName("veth", 7)
181
+	if err != nil {
182
+		t.Fatal(err)
183
+	}
184
+	// veth plus generated append equals a len of 11
185
+	if len(name1) != 11 {
186
+		t.Fatalf("Expected 11 characters, instead received %d characters", len(name1))
187
+	}
188
+	name2, err := GenerateRandomName("veth", 7)
189
+	if err != nil {
190
+		t.Fatal(err)
191
+	}
192
+	// Fail if the random generated names equal one another
193
+	if name1 == name2 {
194
+		t.Fatalf("Expected differing values but received %s and %s", name1, name2)
195
+	}
196
+}
197
+
198
+// Test mac generation.
199
+func TestUtilGenerateRandomMAC(t *testing.T) {
200
+	mac1 := GenerateRandomMAC()
201
+	mac2 := GenerateRandomMAC()
202
+	// ensure bytes are unique
203
+	if bytes.Equal(mac1, mac2) {
204
+		t.Fatalf("mac1 %s should not equal mac2 %s", mac1, mac2)
205
+	}
206
+	// existing tests check string functionality so keeping the pattern
207
+	if mac1.String() == mac2.String() {
208
+		t.Fatalf("mac1 %s should not equal mac2 %s", mac1, mac2)
209
+	}
210
+}