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

Support for consistent MAC address.
This commit is contained in:
Alexandr Morozov 2014-10-03 13:28:03 -07:00
commit beff5067c8
6 changed files with 54 additions and 1 deletions

View file

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

View file

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

View file

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

View file

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

View file

@ -326,10 +326,36 @@ func createBridgeIface(name string) error {
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
func Allocate(job *engine.Job) engine.Status {
var (
ip net.IP
mac net.HardwareAddr
err error
id = job.Args[0]
requestedIP = net.ParseIP(job.Getenv("RequestedIP"))
@ -344,10 +370,16 @@ func Allocate(job *engine.Job) engine.Status {
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.Set("IP", ip.String())
out.Set("Mask", bridgeNetwork.Mask.String())
out.Set("Gateway", bridgeNetwork.IP.String())
out.Set("MacAddress", mac.String())
out.Set("Bridge", bridgeIface)
size, _ := bridgeNetwork.Mask.Size()

View file

@ -102,3 +102,19 @@ func TestHostnameFormatChecking(t *testing.T) {
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")
}
}