// networkReleaseAddress release the ip address func networkReleaseAddress(nwCfg *mastercfg.CfgNetworkState, ipAddress string) error { isIPv6 := netutils.IsIPv6(ipAddress) if isIPv6 { hostID, err := netutils.GetIPv6HostID(nwCfg.SubnetIP, nwCfg.SubnetLen, ipAddress) if err != nil { log.Errorf("error getting host id from hostIP %s Subnet %s/%d. Error: %s", ipAddress, nwCfg.SubnetIP, nwCfg.SubnetLen, err) return err } // networkReleaseAddress is called from multiple places // Make sure we decrement the EpCount only if the IPAddress // was not already freed earlier if _, found := nwCfg.IPv6AllocMap[hostID]; found { nwCfg.EpAddrCount-- } delete(nwCfg.IPv6AllocMap, hostID) } else { ipAddrValue, err := netutils.GetIPNumber(nwCfg.SubnetIP, nwCfg.SubnetLen, 32, ipAddress) if err != nil { log.Errorf("error getting host id from hostIP %s Subnet %s/%d. Error: %s", ipAddress, nwCfg.SubnetIP, nwCfg.SubnetLen, err) return err } // networkReleaseAddress is called from multiple places // Make sure we decrement the EpCount only if the IPAddress // was not already freed earlier if nwCfg.IPAllocMap.Test(ipAddrValue) { nwCfg.EpAddrCount-- } nwCfg.IPAllocMap.Clear(ipAddrValue) } err := nwCfg.Write() if err != nil { log.Errorf("error writing nw config. Error: %s", err) return err } return nil }
// CreateNetwork creates a network from intent func CreateNetwork(network intent.ConfigNetwork, stateDriver core.StateDriver, tenantName string) error { var extPktTag, pktTag uint gCfg := gstate.Cfg{} gCfg.StateDriver = stateDriver err := gCfg.Read("") if err != nil { log.Errorf("error reading tenant cfg state. Error: %s", err) return err } // Create network state networkID := network.Name + "." + tenantName nwCfg := &mastercfg.CfgNetworkState{} nwCfg.StateDriver = stateDriver if nwCfg.Read(networkID) == nil { // TODO: check if parameters changed and apply an update if needed return nil } subnetIP, subnetLen, _ := netutils.ParseCIDR(network.SubnetCIDR) err = netutils.ValidateNetworkRangeParams(subnetIP, subnetLen) if err != nil { return err } ipv6Subnet, ipv6SubnetLen, _ := netutils.ParseCIDR(network.IPv6SubnetCIDR) // construct and update network state nwCfg = &mastercfg.CfgNetworkState{ Tenant: tenantName, NetworkName: network.Name, NwType: network.NwType, PktTagType: network.PktTagType, SubnetIP: subnetIP, SubnetLen: subnetLen, IPv6Subnet: ipv6Subnet, IPv6SubnetLen: ipv6SubnetLen, } nwCfg.ID = networkID nwCfg.StateDriver = stateDriver // Allocate pkt tags reqPktTag := uint(network.PktTag) if nwCfg.PktTagType == "vlan" { pktTag, err = gCfg.AllocVLAN(reqPktTag) if err != nil { return err } } else if nwCfg.PktTagType == "vxlan" { extPktTag, pktTag, err = gCfg.AllocVXLAN(reqPktTag) if err != nil { return err } } nwCfg.ExtPktTag = int(extPktTag) nwCfg.PktTag = int(pktTag) netutils.InitSubnetBitset(&nwCfg.IPAllocMap, nwCfg.SubnetLen) subnetAddr := netutils.GetSubnetAddr(nwCfg.SubnetIP, nwCfg.SubnetLen) nwCfg.SubnetIP = subnetAddr nwCfg.IPAddrRange = netutils.GetIPAddrRange(subnetIP, subnetLen) if network.Gateway != "" { nwCfg.Gateway = network.Gateway // Reserve gateway IP address if gateway is specified ipAddrValue, err := netutils.GetIPNumber(subnetAddr, nwCfg.SubnetLen, 32, nwCfg.Gateway) if err != nil { log.Errorf("Error parsing gateway address %s. Err: %v", nwCfg.Gateway, err) return err } nwCfg.IPAllocMap.Set(ipAddrValue) } if strings.Contains(subnetIP, "-") { netutils.SetBitsOutsideRange(&nwCfg.IPAllocMap, subnetIP, subnetLen) } if network.IPv6Gateway != "" { nwCfg.IPv6Gateway = network.IPv6Gateway // Reserve gateway IPv6 address if gateway is specified hostID, err := netutils.GetIPv6HostID(nwCfg.IPv6Subnet, nwCfg.IPv6SubnetLen, nwCfg.IPv6Gateway) if err != nil { log.Errorf("Error parsing gateway address %s. Err: %v", nwCfg.IPv6Gateway, err) return err } netutils.ReserveIPv6HostID(hostID, &nwCfg.IPv6AllocMap) } err = nwCfg.Write() if err != nil { return err } // Skip docker and service container configs for infra nw if network.NwType == "infra" { return nil } aci, _ := IsAciConfigured() if aci { // Skip docker network creation for ACI fabric mode. return nil } if GetClusterMode() == "docker" { // Create the network in docker err = docknet.CreateDockNet(tenantName, network.Name, "", nwCfg) if err != nil { log.Errorf("Error creating network %s in docker. Err: %v", nwCfg.ID, err) return err } } if IsDNSEnabled() { // Attach service container endpoint to the network err = attachServiceContainer(tenantName, network.Name, stateDriver) if err != nil { log.Errorf("Error attaching service container to network: %s. Err: %v", networkID, err) return err } } return nil }
// Allocate an address from the network func networkAllocAddress(nwCfg *mastercfg.CfgNetworkState, reqAddr string, isIPv6 bool) (string, error) { var ipAddress string var ipAddrValue uint var found bool var err error var hostID string // alloc address if reqAddr == "" { if isIPv6 { // Get the next available IPv6 address hostID, err = netutils.GetNextIPv6HostID(nwCfg.IPv6LastHost, nwCfg.IPv6Subnet, nwCfg.IPv6SubnetLen, nwCfg.IPv6AllocMap) if err != nil { log.Errorf("create eps: error allocating ip. Error: %s", err) return "", err } ipAddress, err = netutils.GetSubnetIPv6(nwCfg.IPv6Subnet, nwCfg.IPv6SubnetLen, hostID) if err != nil { log.Errorf("create eps: error acquiring subnet ip. Error: %s", err) return "", err } nwCfg.IPv6LastHost = hostID } else { ipAddrValue, found = nwCfg.IPAllocMap.NextClear(0) if !found { log.Errorf("auto allocation failed - address exhaustion in subnet %s/%d", nwCfg.SubnetIP, nwCfg.SubnetLen) err = core.Errorf("auto allocation failed - address exhaustion in subnet %s/%d", nwCfg.SubnetIP, nwCfg.SubnetLen) return "", err } ipAddress, err = netutils.GetSubnetIP(nwCfg.SubnetIP, nwCfg.SubnetLen, 32, ipAddrValue) if err != nil { log.Errorf("create eps: error acquiring subnet ip. Error: %s", err) return "", err } } // Docker, Mesos issue a Alloc Address first, followed by a CreateEndpoint // Kubernetes issues a create endpoint directly // since networkAllocAddress is called from both AllocAddressHandler and CreateEndpointHandler, // we need to make sure that the EpCount is incremented only when we are allocating // a new IP. In case of Docker, Mesos CreateEndPoint will already request a IP that // allocateAddress had allocated in the earlier call. nwCfg.EpAddrCount++ } else if reqAddr != "" && nwCfg.SubnetIP != "" { if isIPv6 { hostID, err = netutils.GetIPv6HostID(nwCfg.IPv6Subnet, nwCfg.IPv6SubnetLen, reqAddr) if err != nil { log.Errorf("create eps: error getting host id from hostIP %s Subnet %s/%d. Error: %s", reqAddr, nwCfg.IPv6Subnet, nwCfg.IPv6SubnetLen, err) return "", err } } else { ipAddrValue, err = netutils.GetIPNumber(nwCfg.SubnetIP, nwCfg.SubnetLen, 32, reqAddr) if err != nil { log.Errorf("create eps: error getting host id from hostIP %s Subnet %s/%d. Error: %s", reqAddr, nwCfg.SubnetIP, nwCfg.SubnetLen, err) return "", err } } ipAddress = reqAddr } if isIPv6 { netutils.ReserveIPv6HostID(hostID, &nwCfg.IPv6AllocMap) } else { // Set the bitmap nwCfg.IPAllocMap.Set(ipAddrValue) } err = nwCfg.Write() if err != nil { log.Errorf("error writing nw config. Error: %s", err) return "", err } return ipAddress, nil }