- 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>
| ... | ... |
@@ -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 |
+} |