|
@@ -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()
|