// Allocate a network interface func Allocate(job *engine.Job) engine.Status { var ( ip *net.IP err error id = job.Args[0] requestedIP = net.ParseIP(job.Getenv("RequestedIP")) ) if requestedIP != nil { ip, err = ipallocator.RequestIP(bridgeNetwork, &requestedIP) } else { ip, err = ipallocator.RequestIP(bridgeNetwork, nil) } if err != nil { return job.Error(err) } out := engine.Env{} out.Set("IP", ip.String()) out.Set("Mask", bridgeNetwork.Mask.String()) out.Set("Gateway", bridgeNetwork.IP.String()) out.Set("Bridge", bridgeIface) size, _ := bridgeNetwork.Mask.Size() out.SetInt("IPPrefixLen", size) currentInterfaces.Set(id, &networkInterface{ IP: *ip, }) out.WriteTo(job.Stdout) return engine.StatusOK }
// 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")) ) if requestedIP != nil { ip, err = ipallocator.RequestIP(bridgeNetwork, requestedIP) } else { ip, err = ipallocator.RequestIP(bridgeNetwork, nil) } if err != nil { 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() out.SetInt("IPPrefixLen", size) currentInterfaces.Set(id, &networkInterface{ IP: ip, }) out.WriteTo(job.Stdout) return engine.StatusOK }
func InitDriver(job *engine.Job) engine.Status { var ( networkv4 *net.IPNet networkv6 *net.IPNet addrv4 net.Addr addrsv6 []net.Addr enableIPTables = job.GetenvBool("EnableIptables") enableIPv6 = job.GetenvBool("EnableIPv6") icc = job.GetenvBool("InterContainerCommunication") ipMasq = job.GetenvBool("EnableIpMasq") ipForward = job.GetenvBool("EnableIpForward") bridgeIP = job.Getenv("BridgeIP") bridgeIPv6 = "fe80::1/64" fixedCIDR = job.Getenv("FixedCIDR") fixedCIDRv6 = job.Getenv("FixedCIDRv6") ) if defaultIP := job.Getenv("DefaultBindingIP"); defaultIP != "" { defaultBindingIP = net.ParseIP(defaultIP) } bridgeIface = job.Getenv("BridgeIface") usingDefaultBridge := false if bridgeIface == "" { usingDefaultBridge = true bridgeIface = DefaultNetworkBridge } addrv4, addrsv6, err := networkdriver.GetIfaceAddr(bridgeIface) if err != nil { // No Bridge existent. Create one // If we're not using the default bridge, fail without trying to create it if !usingDefaultBridge { return job.Error(err) } // If the iface is not found, try to create it if err := configureBridge(bridgeIP, bridgeIPv6, enableIPv6); err != nil { return job.Error(err) } addrv4, addrsv6, err = networkdriver.GetIfaceAddr(bridgeIface) if err != nil { return job.Error(err) } if fixedCIDRv6 != "" { // Setting route to global IPv6 subnet log.Infof("Adding route to IPv6 network %q via device %q", fixedCIDRv6, bridgeIface) if err := netlink.AddRoute(fixedCIDRv6, "", "", bridgeIface); err != nil { log.Fatalf("Could not add route to IPv6 network %q via device %q", fixedCIDRv6, bridgeIface) } } } else { // Bridge exists already. Getting info... // validate that the bridge ip matches the ip specified by BridgeIP if bridgeIP != "" { networkv4 = addrv4.(*net.IPNet) bip, _, err := net.ParseCIDR(bridgeIP) if err != nil { return job.Error(err) } if !networkv4.IP.Equal(bip) { return job.Errorf("bridge ip (%s) does not match existing bridge configuration %s", networkv4.IP, bip) } } // a bridge might exist but not have any IPv6 addr associated with it yet // (for example, an existing Docker installation that has only been used // with IPv4 and docker0 already is set up) In that case, we can perform // the bridge init for IPv6 here, else we will error out below if --ipv6=true if len(addrsv6) == 0 && enableIPv6 { if err := setupIPv6Bridge(bridgeIPv6); err != nil { return job.Error(err) } // recheck addresses now that IPv6 is setup on the bridge addrv4, addrsv6, err = networkdriver.GetIfaceAddr(bridgeIface) if err != nil { return job.Error(err) } } // TODO: Check if route to fixedCIDRv6 is set } if enableIPv6 { bip6, _, err := net.ParseCIDR(bridgeIPv6) if err != nil { return job.Error(err) } found := false for _, addrv6 := range addrsv6 { networkv6 = addrv6.(*net.IPNet) if networkv6.IP.Equal(bip6) { found = true break } } if !found { return job.Errorf("bridge IPv6 does not match existing bridge configuration %s", bip6) } } networkv4 = addrv4.(*net.IPNet) log.Infof("enableIPv6 = %t", enableIPv6) if enableIPv6 { if len(addrsv6) == 0 { return job.Error(errors.New("IPv6 enabled but no IPv6 detected")) } bridgeIPv6Addr = networkv6.IP } // Configure iptables for link support if enableIPTables { if err := setupIPTables(addrv4, icc, ipMasq); err != nil { return job.Error(err) } } if ipForward { // Enable IPv4 forwarding if err := ioutil.WriteFile("/proc/sys/net/ipv4/ip_forward", []byte{'1', '\n'}, 0644); err != nil { job.Logf("WARNING: unable to enable IPv4 forwarding: %s\n", err) } if fixedCIDRv6 != "" { // Enable IPv6 forwarding if err := ioutil.WriteFile("/proc/sys/net/ipv6/conf/default/forwarding", []byte{'1', '\n'}, 0644); err != nil { job.Logf("WARNING: unable to enable IPv6 default forwarding: %s\n", err) } if err := ioutil.WriteFile("/proc/sys/net/ipv6/conf/all/forwarding", []byte{'1', '\n'}, 0644); err != nil { job.Logf("WARNING: unable to enable IPv6 all forwarding: %s\n", err) } } } // We can always try removing the iptables if err := iptables.RemoveExistingChain("DOCKER", iptables.Nat); err != nil { return job.Error(err) } if enableIPTables { _, err := iptables.NewChain("DOCKER", bridgeIface, iptables.Nat) if err != nil { return job.Error(err) } chain, err := iptables.NewChain("DOCKER", bridgeIface, iptables.Filter) if err != nil { return job.Error(err) } portmapper.SetIptablesChain(chain) } bridgeIPv4Network = networkv4 if fixedCIDR != "" { _, subnet, err := net.ParseCIDR(fixedCIDR) if err != nil { return job.Error(err) } log.Debugf("Subnet: %v", subnet) if err := ipallocator.RegisterSubnet(bridgeIPv4Network, subnet); err != nil { return job.Error(err) } } if fixedCIDRv6 != "" { _, subnet, err := net.ParseCIDR(fixedCIDRv6) if err != nil { return job.Error(err) } log.Debugf("Subnet: %v", subnet) if err := ipallocator.RegisterSubnet(subnet, subnet); err != nil { return job.Error(err) } globalIPv6Network = subnet } // Block BridgeIP in IP allocator ipallocator.RequestIP(bridgeIPv4Network, bridgeIPv4Network.IP) // https://github.com/docker/docker/issues/2768 job.Eng.Hack_SetGlobalVar("httpapi.bridgeIP", bridgeIPv4Network.IP) for name, f := range map[string]engine.Handler{ "allocate_interface": Allocate, "release_interface": Release, "allocate_port": AllocatePort, "link": LinkContainers, } { if err := job.Eng.Register(name, f); err != nil { return job.Error(err) } } return engine.StatusOK }
// 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")) requestedIPv6 = net.ParseIP(job.Getenv("RequestedIPv6")) globalIPv6 net.IP ) if requestedIP != nil { ip, err = ipallocator.RequestIP(bridgeIPv4Network, requestedIP) } else { ip, err = ipallocator.RequestIP(bridgeIPv4Network, nil) } if err != nil { 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) } if globalIPv6Network != nil { // if globalIPv6Network Size is at least a /80 subnet generate IPv6 address from MAC address netmask_ones, _ := globalIPv6Network.Mask.Size() if requestedIPv6 == nil && netmask_ones <= 80 { requestedIPv6 = globalIPv6Network.IP for i, h := range mac { requestedIPv6[i+10] = h } } globalIPv6, err = ipallocator.RequestIP(globalIPv6Network, requestedIPv6) if err != nil { log.Errorf("Allocator: RequestIP v6: %s", err.Error()) return job.Error(err) } log.Infof("Allocated IPv6 %s", globalIPv6) } out := engine.Env{} out.Set("IP", ip.String()) out.Set("Mask", bridgeIPv4Network.Mask.String()) out.Set("Gateway", bridgeIPv4Network.IP.String()) out.Set("MacAddress", mac.String()) out.Set("Bridge", bridgeIface) size, _ := bridgeIPv4Network.Mask.Size() out.SetInt("IPPrefixLen", size) // if linklocal IPv6 localIPv6Net, err := linkLocalIPv6FromMac(mac.String()) if err != nil { return job.Error(err) } localIPv6, _, _ := net.ParseCIDR(localIPv6Net) out.Set("LinkLocalIPv6", localIPv6.String()) out.Set("MacAddress", mac.String()) if globalIPv6Network != nil { out.Set("GlobalIPv6", globalIPv6.String()) sizev6, _ := globalIPv6Network.Mask.Size() out.SetInt("GlobalIPv6PrefixLen", sizev6) out.Set("IPv6Gateway", bridgeIPv6Addr.String()) } currentInterfaces.Set(id, &networkInterface{ IP: ip, IPv6: globalIPv6, }) out.WriteTo(job.Stdout) return engine.StatusOK }