Browse Source

Merge pull request #8371 from aluzzardi/f-consistent-mac

Support for consistent MAC address.
Alexandr Morozov 10 năm trước cách đây
mục cha
commit
beff5067c8

+ 2 - 0
daemon/container.go

@@ -215,6 +215,7 @@ func populateCommand(c *Container, env []string) error {
 				Bridge:      network.Bridge,
 				Bridge:      network.Bridge,
 				IPAddress:   network.IPAddress,
 				IPAddress:   network.IPAddress,
 				IPPrefixLen: network.IPPrefixLen,
 				IPPrefixLen: network.IPPrefixLen,
+				MacAddress:  network.MacAddress,
 			}
 			}
 		}
 		}
 	case "container":
 	case "container":
@@ -504,6 +505,7 @@ func (container *Container) allocateNetwork() error {
 	container.NetworkSettings.Bridge = env.Get("Bridge")
 	container.NetworkSettings.Bridge = env.Get("Bridge")
 	container.NetworkSettings.IPAddress = env.Get("IP")
 	container.NetworkSettings.IPAddress = env.Get("IP")
 	container.NetworkSettings.IPPrefixLen = env.GetInt("IPPrefixLen")
 	container.NetworkSettings.IPPrefixLen = env.GetInt("IPPrefixLen")
+	container.NetworkSettings.MacAddress = env.Get("MacAddress")
 	container.NetworkSettings.Gateway = env.Get("Gateway")
 	container.NetworkSettings.Gateway = env.Get("Gateway")
 
 
 	return nil
 	return nil

+ 2 - 1
daemon/execdriver/driver.go

@@ -65,8 +65,9 @@ type Network struct {
 type NetworkInterface struct {
 type NetworkInterface struct {
 	Gateway     string `json:"gateway"`
 	Gateway     string `json:"gateway"`
 	IPAddress   string `json:"ip"`
 	IPAddress   string `json:"ip"`
-	Bridge      string `json:"bridge"`
 	IPPrefixLen int    `json:"ip_prefix_len"`
 	IPPrefixLen int    `json:"ip_prefix_len"`
+	MacAddress  string `json:"mac_address"`
+	Bridge      string `json:"bridge"`
 }
 }
 
 
 type Resources struct {
 type Resources struct {

+ 1 - 0
daemon/execdriver/native/create.go

@@ -95,6 +95,7 @@ func (d *driver) createNetwork(container *libcontainer.Config, c *execdriver.Com
 		vethNetwork := libcontainer.Network{
 		vethNetwork := libcontainer.Network{
 			Mtu:        c.Network.Mtu,
 			Mtu:        c.Network.Mtu,
 			Address:    fmt.Sprintf("%s/%d", c.Network.Interface.IPAddress, c.Network.Interface.IPPrefixLen),
 			Address:    fmt.Sprintf("%s/%d", c.Network.Interface.IPAddress, c.Network.Interface.IPPrefixLen),
+			MacAddress: c.Network.Interface.MacAddress,
 			Gateway:    c.Network.Interface.Gateway,
 			Gateway:    c.Network.Interface.Gateway,
 			Type:       "veth",
 			Type:       "veth",
 			Bridge:     c.Network.Interface.Bridge,
 			Bridge:     c.Network.Interface.Bridge,

+ 1 - 0
daemon/network_settings.go

@@ -11,6 +11,7 @@ type PortMapping map[string]string // Deprecated
 type NetworkSettings struct {
 type NetworkSettings struct {
 	IPAddress   string
 	IPAddress   string
 	IPPrefixLen int
 	IPPrefixLen int
+	MacAddress  string
 	Gateway     string
 	Gateway     string
 	Bridge      string
 	Bridge      string
 	PortMapping map[string]PortMapping // Deprecated
 	PortMapping map[string]PortMapping // Deprecated

+ 32 - 0
daemon/networkdriver/bridge/driver.go

@@ -326,10 +326,36 @@ func createBridgeIface(name string) error {
 	return netlink.CreateBridge(name, setBridgeMacAddr)
 	return netlink.CreateBridge(name, setBridgeMacAddr)
 }
 }
 
 
+// Generate a IEEE802 compliant MAC address from the given IP address.
+//
+// The generator is guaranteed to be consistent: the same IP will always yield the same
+// MAC address. This is to avoid ARP cache issues.
+func generateMacAddr(ip net.IP) net.HardwareAddr {
+	hw := make(net.HardwareAddr, 6)
+
+	// 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
+
+	// Insert the IP address into the last 32 bits of the MAC address.
+	// This is a simple way to guarantee the address will be consistent and unique.
+	copy(hw[2:], ip.To4())
+
+	return hw
+}
+
 // Allocate a network interface
 // Allocate a network interface
 func Allocate(job *engine.Job) engine.Status {
 func Allocate(job *engine.Job) engine.Status {
 	var (
 	var (
 		ip          net.IP
 		ip          net.IP
+		mac         net.HardwareAddr
 		err         error
 		err         error
 		id          = job.Args[0]
 		id          = job.Args[0]
 		requestedIP = net.ParseIP(job.Getenv("RequestedIP"))
 		requestedIP = net.ParseIP(job.Getenv("RequestedIP"))
@@ -344,10 +370,16 @@ func Allocate(job *engine.Job) engine.Status {
 		return job.Error(err)
 		return job.Error(err)
 	}
 	}
 
 
+	// If no explicit mac address was given, generate a random one.
+	if mac, err = net.ParseMAC(job.Getenv("RequestedMac")); err != nil {
+		mac = generateMacAddr(ip)
+	}
+
 	out := engine.Env{}
 	out := engine.Env{}
 	out.Set("IP", ip.String())
 	out.Set("IP", ip.String())
 	out.Set("Mask", bridgeNetwork.Mask.String())
 	out.Set("Mask", bridgeNetwork.Mask.String())
 	out.Set("Gateway", bridgeNetwork.IP.String())
 	out.Set("Gateway", bridgeNetwork.IP.String())
+	out.Set("MacAddress", mac.String())
 	out.Set("Bridge", bridgeIface)
 	out.Set("Bridge", bridgeIface)
 
 
 	size, _ := bridgeNetwork.Mask.Size()
 	size, _ := bridgeNetwork.Mask.Size()

+ 16 - 0
daemon/networkdriver/bridge/driver_test.go

@@ -102,3 +102,19 @@ func TestHostnameFormatChecking(t *testing.T) {
 		t.Fatal("Failed to check invalid HostIP")
 		t.Fatal("Failed to check invalid HostIP")
 	}
 	}
 }
 }
+
+func TestMacAddrGeneration(t *testing.T) {
+	ip := net.ParseIP("192.168.0.1")
+	mac := generateMacAddr(ip).String()
+
+	// Should be consistent.
+	if generateMacAddr(ip).String() != mac {
+		t.Fatal("Inconsistent MAC address")
+	}
+
+	// Should be unique.
+	ip2 := net.ParseIP("192.168.0.2")
+	if generateMacAddr(ip2).String() == mac {
+		t.Fatal("Non-unique MAC address")
+	}
+}