Пример #1
0
func freeNetworkResources(stateDriver core.StateDriver, nwMasterCfg *NwConfig,
	nwCfg *drivers.OvsCfgNetworkState, gCfg *gstate.Cfg) (err error) {

	tempRm, err := resources.GetStateResourceManager()
	if err != nil {
		return err
	}
	rm := core.ResourceManager(tempRm)

	if nwCfg.PktTagType == "vlan" {
		err = gCfg.FreeVLAN(rm, uint(nwCfg.PktTag))
		if err != nil {
			return err
		}
	} else if nwCfg.PktTagType == "vxlan" {
		log.Infof("freeing vlan %d vxlan %d", nwCfg.PktTag, nwCfg.ExtPktTag)
		err = gCfg.FreeVXLAN(rm, uint(nwCfg.ExtPktTag), uint(nwCfg.PktTag))
		if err != nil {
			return err
		}
	}

	if nwMasterCfg.SubnetIP == "" {
		log.Infof("freeing subnet %s/%s", nwCfg.SubnetIP, nwCfg.SubnetLen)
		err = gCfg.FreeSubnet(rm, nwCfg.SubnetIP)
		if err != nil {
			return err
		}
	}

	return err
}
Пример #2
0
// AllocVXLAN allocates a new vxlan; ids for both the vxlan and vlan are returned.
func (gc *Cfg) AllocVXLAN(reqVxlan uint) (vxlan uint, localVLAN uint, err error) {

	tempRm, err := resources.GetStateResourceManager()
	if err != nil {
		return 0, 0, err
	}
	ra := core.ResourceManager(tempRm)

	g := &Oper{}
	g.StateDriver = gc.StateDriver
	err = g.Read("")
	if err != nil {
		return 0, 0, err
	}

	if reqVxlan != 0 && reqVxlan <= g.FreeVXLANsStart {
		return 0, 0, errors.New("Requested vxlan is out of range")
	}

	if (reqVxlan != 0) && (reqVxlan >= g.FreeVXLANsStart) {
		reqVxlan = reqVxlan - g.FreeVXLANsStart
	}

	pair, err1 := ra.AllocateResourceVal("global", resources.AutoVXLANResource, reqVxlan)
	if err1 != nil {
		return 0, 0, err1
	}

	vxlan = pair.(resources.VXLANVLANPair).VXLAN + g.FreeVXLANsStart
	localVLAN = pair.(resources.VXLANVLANPair).VLAN

	return
}
Пример #3
0
func freeNetworkResources(stateDriver core.StateDriver, nwCfg *mastercfg.CfgNetworkState, gCfg *gstate.Cfg) (err error) {

	tempRm, err := resources.GetStateResourceManager()
	if err != nil {
		return err
	}
	rm := core.ResourceManager(tempRm)

	if nwCfg.PktTagType == "vlan" {
		err = gCfg.FreeVLAN(rm, uint(nwCfg.PktTag))
		if err != nil {
			return err
		}
	} else if nwCfg.PktTagType == "vxlan" {
		log.Infof("freeing vlan %d vxlan %d", nwCfg.PktTag, nwCfg.ExtPktTag)
		err = gCfg.FreeVXLAN(rm, uint(nwCfg.ExtPktTag), uint(nwCfg.PktTag))
		if err != nil {
			return err
		}
	}

	if nwCfg.SubnetIsAllocated {
		log.Infof("freeing subnet %s/%d", nwCfg.SubnetIP, nwCfg.SubnetLen)
		err = gCfg.FreeSubnet(rm, nwCfg.SubnetIP)
		if err != nil {
			return err
		}
	}

	if err := gCfg.UnassignNetwork(nwCfg.ID); err != nil {
		return err
	}

	return err
}
Пример #4
0
// FreeVLAN releases a VLAN for a given ID.
func (gc *Cfg) FreeVLAN(vlan uint) error {
	tempRm, err := resources.GetStateResourceManager()
	if err != nil {
		return err
	}
	ra := core.ResourceManager(tempRm)

	return ra.DeallocateResourceVal("global", resources.AutoVLANResource, vlan)
}
Пример #5
0
// Process validates, implements, and writes the state.
func (gc *Cfg) Process(res string) error {
	var err error

	tempRm, err := resources.GetStateResourceManager()
	if err != nil {
		return err
	}

	ra := core.ResourceManager(tempRm)

	err = gc.checkErrors(res)
	if err != nil {
		return core.Errorf("process failed on error checks %s", err)
	}

	// Only define a vlan resource if a valid range was specified
	if res == "vlan" {
		if gc.Auto.VLANs != "" {
			var vlanRsrcCfg *bitset.BitSet
			vlanRsrcCfg, err = gc.initVLANBitset(gc.Auto.VLANs)
			if err != nil {
				return err
			}
			err = ra.DefineResource("global", resources.AutoVLANResource, vlanRsrcCfg)
			if err != nil {
				return err
			}
		}
	}
	// Only define a vxlan resource if a valid range was specified
	var freeVXLANsStart uint
	if res == "vxlan" {
		if gc.Auto.VXLANs != "" {
			var vxlanRsrcCfg *resources.AutoVXLANCfgResource
			vxlanRsrcCfg, freeVXLANsStart, err = gc.initVXLANBitset(gc.Auto.VXLANs)
			if err != nil {
				return err
			}
			err = ra.DefineResource("global", resources.AutoVXLANResource, vxlanRsrcCfg)
			if err != nil {
				return err
			}
		}

		g := &Oper{FreeVXLANsStart: freeVXLANsStart}

		g.StateDriver = gc.StateDriver
		err = g.Write()
		if err != nil {
			log.Errorf("error '%s' updating global oper state %v \n", err, g)
			return err
		}
	}

	log.Debugf("updating the global config to new state %v \n", gc)
	return nil
}
Пример #6
0
// GetVlansInUse gets the vlans that are currently in use
func (gc *Cfg) GetVlansInUse() (uint, string) {
	tempRm, err := resources.GetStateResourceManager()
	if err != nil {
		log.Errorf("error getting resource manager: %s", err)
		return 0, ""
	}
	ra := core.ResourceManager(tempRm)

	return ra.GetResourceList("global", resources.AutoVLANResource)
}
Пример #7
0
// DeleteEndpointGroup handles endpoint group deletes
func DeleteEndpointGroup(epgID int) error {
	// Get the state driver
	stateDriver, err := utils.GetStateDriver()
	if err != nil {
		return err
	}

	epgCfg := &mastercfg.EndpointGroupState{}
	epgCfg.StateDriver = stateDriver
	err = epgCfg.Read(strconv.Itoa(epgID))
	if err != nil {
		log.Errorf("EpGroup %v is not configured", epgID)
		return err
	}

	gCfg := gstate.Cfg{}
	gCfg.StateDriver = stateDriver
	err = gCfg.Read(epgCfg.Tenant)
	if err != nil {
		log.Errorf("error reading tenant cfg state. Error: %s", err)
		return err
	}

	// if aci mode we allocate per-epg vlan. free it here.
	aciMode, aErr := IsAciConfigured()
	if aErr != nil {
		return aErr
	}

	if aciMode {
		tempRm, rErr := resources.GetStateResourceManager()
		if rErr != nil {
			return rErr
		}
		rm := core.ResourceManager(tempRm)
		if epgCfg.PktTagType == "vlan" {
			err = gCfg.FreeVLAN(rm, uint(epgCfg.PktTag))
			if err != nil {
				return err
			}
			log.Debugf("Freed vlan %v\n", epgCfg.PktTag)
		}
	}

	epgNet := epgCfg.Name + "." + epgCfg.NetworkName + "." + epgCfg.Tenant

	err = epgCfg.Clear()
	if err != nil {
		log.Errorf("error writing epGroup config. Error: %v", err)
		return err
	}

	return deleteDockNet(epgNet)
}
Пример #8
0
// CreateTenant sets the tenant's state according to the passed ConfigTenant.
func CreateTenant(stateDriver core.StateDriver, tenant *intent.ConfigTenant) error {
	gOper := &gstate.Oper{}
	gOper.StateDriver = stateDriver
	err := gOper.Read(tenant.Name)
	if err == nil {
		return err
	}

	err = validateTenantConfig(tenant)
	if err != nil {
		return err
	}

	gCfg := &gstate.Cfg{}
	gCfg.StateDriver = stateDriver
	gCfg.Version = gstate.VersionBeta1
	gCfg.Tenant = tenant.Name
	gCfg.Deploy.DefaultNetType = tenant.DefaultNetType
	gCfg.Deploy.DefaultNetwork = tenant.DefaultNetwork
	gCfg.Auto.SubnetPool, gCfg.Auto.SubnetLen, _ = netutils.ParseCIDR(tenant.SubnetPool)
	gCfg.Auto.VLANs = tenant.VLANs
	gCfg.Auto.VXLANs = tenant.VXLANs
	gCfg.Auto.AllocSubnetLen = tenant.AllocSubnetLen

	tempRm, err := resources.GetStateResourceManager()
	if err != nil {
		return err
	}

	// setup resources
	err = gCfg.Process(core.ResourceManager(tempRm))
	if err != nil {
		log.Errorf("Error updating the config %+v. Error: %s", gCfg, err)
		return err
	}

	// start skydns container
	err = startServiceContainer(tenant.Name)
	if err != nil {
		log.Errorf("Error starting service container. Err: %v", err)
		return err
	}

	err = gCfg.Write()
	if err != nil {
		log.Errorf("error updating tenant '%s'.Error: %s", tenant.Name, err)
		return err
	}

	return nil
}
Пример #9
0
// AllocVLAN allocates a new VLAN resource. Returns an ID.
func (gc *Cfg) AllocVLAN(reqVlan uint) (uint, error) {
	tempRm, err := resources.GetStateResourceManager()
	if err != nil {
		return 0, err
	}
	ra := core.ResourceManager(tempRm)

	vlan, err := ra.AllocateResourceVal("global", resources.AutoVLANResource, reqVlan)
	if err != nil {
		log.Errorf("alloc vlan failed: %q", err)
		return 0, err
	}

	return vlan.(uint), err
}
Пример #10
0
// UpdateResources deletes associated resources
func (gc *Cfg) UpdateResources(res string) error {
	log.Infof("Received update resource for res %s", res)
	tempRm, err := resources.GetStateResourceManager()
	if err != nil {
		return err
	}

	ra := core.ResourceManager(tempRm)

	err = gc.checkErrors(res)
	if err != nil {
		return core.Errorf("process failed on error checks %s", err)
	}

	if res == "vlan" {
		var vlanRsrcCfg *bitset.BitSet
		vlanRsrcCfg, err = gc.initVLANBitset(gc.Auto.VLANs)
		if err != nil {
			return err
		}
		err = ra.RedefineResource("global", resources.AutoVLANResource, vlanRsrcCfg)
		if err != nil {
			log.Errorf("Error deleting vlan resource. Err: %v", err)
		}
	} else if res == "vxlan" {
		var vxlanRsrcCfg *resources.AutoVXLANCfgResource
		vxlanRsrcCfg, err = gc.initVXLANBitset(gc.Auto.VXLANs)
		if err != nil {
			return err
		}
		err = ra.RedefineResource("global", resources.AutoVXLANResource, vxlanRsrcCfg)
		if err != nil {
			log.Errorf("Error deleting vxlan resource. Err: %v", err)
		}
		g := &Oper{FreeVXLANsStart: vxlanRsrcCfg.FreeVXLANsStart}

		g.StateDriver = gc.StateDriver
		err = g.Write()
		if err != nil {
			log.Errorf("error '%s' updating global oper state %v \n", err, g)
			return err
		}
	}
	return err
}
Пример #11
0
// DeleteTenantID deletes a tenant from the state store, by ID.
func DeleteTenantID(stateDriver core.StateDriver, tenantID string) error {
	gOper := &gstate.Oper{}
	gOper.StateDriver = stateDriver
	err := gOper.Read(tenantID)
	if err != nil {
		log.Errorf("error reading tenant info '%s'. Error: %s", tenantID, err)
		return err
	}

	err = stopAndRemoveServiceContainer(tenantID)
	if err != nil {
		log.Errorf("Error in stopping service container for tenant: %+v", tenantID)
		return err
	}

	gCfg := &gstate.Cfg{}
	gCfg.StateDriver = stateDriver
	err = gCfg.Read(tenantID)
	if err != nil {
		log.Errorf("error reading tenant config '%s'. Error: %s", tenantID, err)
		return err
	}

	tempRm, err := resources.GetStateResourceManager()
	if err == nil {
		err = gCfg.DeleteResources(core.ResourceManager(tempRm))
		if err != nil {
			log.Errorf("Error deleting the config %+v. Error: %s", gCfg, err)
		}
	}

	// delete tenant config
	err = gCfg.Clear()
	if err != nil {
		log.Errorf("error deleting cfg for tenant %q: Error: %s", tenantID, err)
	}

	err = gOper.Clear()
	if err != nil {
		log.Errorf("error deleting oper for tenant %q: Error: %s", tenantID, err)
	}

	return err
}
Пример #12
0
// FreeVXLAN returns a VXLAN id to the pool.
func (gc *Cfg) FreeVXLAN(vxlan uint, localVLAN uint) error {
	tempRm, err := resources.GetStateResourceManager()
	if err != nil {
		return err
	}
	ra := core.ResourceManager(tempRm)

	g := &Oper{}
	g.StateDriver = gc.StateDriver
	err = g.Read("")
	if err != nil {
		return nil
	}

	return ra.DeallocateResourceVal("global", resources.AutoVXLANResource,
		resources.VXLANVLANPair{
			VXLAN: vxlan - g.FreeVXLANsStart,
			VLAN:  localVLAN})
}
Пример #13
0
// DeleteResources deletes associated resources
func (gc *Cfg) DeleteResources() error {
	tempRm, err := resources.GetStateResourceManager()
	if err != nil {
		return err
	}

	ra := core.ResourceManager(tempRm)

	err = ra.UndefineResource("global", resources.AutoVLANResource)
	if err != nil {
		log.Errorf("Error deleting vlan resource. Err: %v", err)
	}

	err = ra.UndefineResource("global", resources.AutoVXLANResource)
	if err != nil {
		log.Errorf("Error deleting vxlan resource. Err: %v", err)
	}

	return err
}
Пример #14
0
// 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(tenantName)
	if err != nil {
		log.Errorf("error reading tenant cfg state. Error: %s", err)
		return err
	}

	tempRm, err := resources.GetStateResourceManager()
	if err != nil {
		return err
	}
	rm := core.ResourceManager(tempRm)

	// Create network state
	nwCfg := &drivers.OvsCfgNetworkState{}
	nwCfg.StateDriver = stateDriver
	if nwCfg.Read(network.Name) == nil {
		// TODO: check if parameters changed and apply an update if needed
		return nil
	}

	// construct and update network state
	nwMasterCfg := &NwConfig{}
	nwMasterCfg.StateDriver = stateDriver
	nwMasterCfg.Tenant = tenantName
	nwMasterCfg.ID = network.Name
	nwMasterCfg.PktTagType = network.PktTagType
	nwMasterCfg.PktTag = network.PktTag
	nwMasterCfg.SubnetIP, nwMasterCfg.SubnetLen, _ = netutils.ParseCIDR(network.SubnetCIDR)
	nwMasterCfg.DefaultGw = network.DefaultGw

	nwCfg = &drivers.OvsCfgNetworkState{
		Tenant:     nwMasterCfg.Tenant,
		PktTagType: nwMasterCfg.PktTagType,
		SubnetIP:   nwMasterCfg.SubnetIP,
		SubnetLen:  nwMasterCfg.SubnetLen,
	}
	nwCfg.StateDriver = stateDriver
	nwCfg.ID = nwMasterCfg.ID

	if nwMasterCfg.PktTagType == "" {
		nwCfg.PktTagType = gCfg.Deploy.DefaultNetType
	}
	if nwMasterCfg.PktTag == "" {
		if nwCfg.PktTagType == "vlan" {
			pktTag, err = gCfg.AllocVLAN(rm)
			if err != nil {
				return err
			}
		} else if nwCfg.PktTagType == "vxlan" {
			extPktTag, pktTag, err = gCfg.AllocVXLAN(rm)
			if err != nil {
				return err
			}
		}

		nwCfg.ExtPktTag = int(extPktTag)
		nwCfg.PktTag = int(pktTag)
	} else if nwMasterCfg.PktTagType == "vxlan" {
		// XXX: take local vlan as config, instead of allocating it
		// independently. Return erro for now, if user tries this config
		return core.Errorf("Not handled. Need to introduce local-vlan config")
	} else if nwMasterCfg.PktTagType == "vlan" {
		nwCfg.PktTag, _ = strconv.Atoi(nwMasterCfg.PktTag)
		// XXX: do configuration check, to make sure it is allowed
	}

	if nwCfg.SubnetIP == "" {
		nwCfg.SubnetLen = gCfg.Auto.AllocSubnetLen
		nwCfg.SubnetIP, err = gCfg.AllocSubnet(rm)
		if err != nil {
			return err
		}
	}

	nwCfg.DefaultGw = network.DefaultGw
	if nwCfg.DefaultGw == "" {
		// TBD: allocate per global policy
	}

	netutils.InitSubnetBitset(&nwCfg.IPAllocMap, nwCfg.SubnetLen)
	err = nwCfg.Write()
	if err != nil {
		return err
	}

	err = nwMasterCfg.Write()
	if err != nil {
		log.Errorf("error writing nw config. Error: %s", err)
		return err
	}

	if nwCfg.PktTagType == "vxlan" {

		readHost := &HostConfig{}
		readHost.StateDriver = stateDriver
		hostCfgs, err := readHost.ReadAll()
		if err != nil {
			if !strings.Contains(err.Error(), "Key not found") {
				log.Errorf("error reading hosts during net add. Error: %s", err)
			}
		}
		for _, hostCfg := range hostCfgs {
			host := hostCfg.(*HostConfig)
			err = createVtep(stateDriver, host, nwCfg.ID)
			if err != nil {
				log.Errorf("error creating vtep. Error: %s", err)
			}
		}
	}

	return nil
}
Пример #15
0
// CreateEndpointGroup handles creation of endpoint group
func CreateEndpointGroup(tenantName, networkName, groupName string, epgID int) error {
	// Get the state driver
	stateDriver, err := utils.GetStateDriver()
	if err != nil {
		return err
	}

	// Read global config
	gCfg := gstate.Cfg{}
	gCfg.StateDriver = stateDriver
	err = gCfg.Read(tenantName)
	if err != nil {
		log.Errorf("error reading tenant cfg state. Error: %s", err)
		return err
	}

	// read the network config
	networkID := networkName + "." + tenantName
	nwCfg := &mastercfg.CfgNetworkState{}
	nwCfg.StateDriver = stateDriver
	err = nwCfg.Read(networkID)
	if err != nil {
		log.Errorf("Could not find network %s. Err: %v", networkID, err)
		return err
	}

	// params for docker network
	if GetClusterMode() == "docker" {
		subnetCIDR := fmt.Sprintf("%s/%d", nwCfg.SubnetIP, nwCfg.SubnetLen)

		// Create each EPG as a docker network
		err = createDockNet(tenantName, networkName, groupName, subnetCIDR, nwCfg.Gateway)
		if err != nil {
			log.Errorf("Error creating docker network for group %s.%s. Err: %v", networkName, groupName, err)
			return err
		}
	}

	// Get resource manager
	tempRm, err := resources.GetStateResourceManager()
	if err != nil {
		return err
	}
	rm := core.ResourceManager(tempRm)

	// Create epGroup state
	epgCfg := &mastercfg.EndpointGroupState{
		Name:        groupName,
		Tenant:      tenantName,
		NetworkName: networkName,
		PktTagType:  nwCfg.PktTagType,
		PktTag:      nwCfg.PktTag,
		ExtPktTag:   nwCfg.ExtPktTag,
	}

	epgCfg.StateDriver = stateDriver
	epgCfg.ID = strconv.Itoa(epgID)
	log.Debugf("##Create EpGroup %v network %v tagtype %v", groupName, networkName, nwCfg.PktTagType)

	// if aci mode allocate per-epg vlan. otherwise, stick to per-network vlan
	aciMode, rErr := IsAciConfigured()
	if rErr != nil {
		return rErr
	}

	// Special handling for ACI mode
	if aciMode {
		if epgCfg.PktTagType != "vlan" {
			log.Errorf("Network type must be VLAN for ACI mode")
			return errors.New("Network type must be VLAN for ACI mode")
		}

		pktTag, err := gCfg.AllocVLAN(rm)
		if err != nil {
			return err
		}
		epgCfg.PktTag = int(pktTag)
		log.Debugf("ACI -- Allocated vlan %v for epg %v", pktTag, groupName)

	}

	err = epgCfg.Write()
	if err != nil {
		return err
	}

	return nil
}
Пример #16
0
// 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(tenantName)
	if err != nil {
		log.Errorf("error reading tenant cfg state. Error: %s", err)
		return err
	}

	tempRm, err := resources.GetStateResourceManager()
	if err != nil {
		return err
	}
	rm := core.ResourceManager(tempRm)

	// 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)

	// construct and update network state
	nwCfg = &mastercfg.CfgNetworkState{
		Tenant:      tenantName,
		NetworkName: network.Name,
		PktTagType:  network.PktTagType,
		SubnetIP:    subnetIP,
		SubnetLen:   subnetLen,
		Gateway:     network.Gateway,
	}

	nwCfg.ID = networkID
	nwCfg.StateDriver = stateDriver

	if network.PktTagType == "" {
		nwCfg.PktTagType = gCfg.Deploy.DefaultNetType
	}
	if network.PktTag == 0 {
		if nwCfg.PktTagType == "vlan" {
			pktTag, err = gCfg.AllocVLAN(rm)
			if err != nil {
				return err
			}
		} else if nwCfg.PktTagType == "vxlan" {
			extPktTag, pktTag, err = gCfg.AllocVXLAN(rm)
			if err != nil {
				return err
			}
		}

		nwCfg.ExtPktTag = int(extPktTag)
		nwCfg.PktTag = int(pktTag)
	} else if network.PktTagType == "vxlan" {
		if !isTagInRange(uint(network.PktTag), "vxlan", gCfg.Auto.VXLANs, stateDriver, tenantName) {
			return fmt.Errorf("vxlan %d does not adhere to tenant's vxlan range %s", network.PktTag, gCfg.Auto.VXLANs)
		}

		nwCfg.ExtPktTag = network.PktTag
		nwCfg.PktTag = network.PktTag
	} else if network.PktTagType == "vlan" {

		if !isTagInRange(uint(network.PktTag), "vlan", gCfg.Auto.VLANs, stateDriver, tenantName) {
			return fmt.Errorf("vlan %d does not adhere to tenant's vlan range %s", network.PktTag, gCfg.Auto.VLANs)
		}
		nwCfg.PktTag = network.PktTag
	}

	if nwCfg.SubnetIP == "" {
		nwCfg.SubnetLen = gCfg.Auto.AllocSubnetLen
		nwCfg.SubnetIP, err = gCfg.AllocSubnet(rm)
		if err != nil {
			return err
		}
		nwCfg.SubnetIsAllocated = true
	}

	defaultNwName, err := gCfg.AssignDefaultNetwork(network.Name)
	if err != nil {
		log.Errorf("error assigning the default network. Error: %s", err)
		return err
	}

	if network.Name == defaultNwName {
		// For auto derived subnets assign gateway ip be the last valid unicast ip the subnet
		if nwCfg.Gateway == "" && nwCfg.SubnetIsAllocated {
			var ipAddrValue uint
			ipAddrValue = (1 << (32 - nwCfg.SubnetLen)) - 2
			nwCfg.Gateway, err = netutils.GetSubnetIP(nwCfg.SubnetIP, nwCfg.SubnetLen, 32, ipAddrValue)
			if err != nil {
				return err
			}
			nwCfg.IPAllocMap.Set(ipAddrValue)
		}
	}

	netutils.InitSubnetBitset(&nwCfg.IPAllocMap, nwCfg.SubnetLen)
	err = nwCfg.Write()
	if err != nil {
		return err
	}

	if GetClusterMode() == "docker" {
		// Create the network in docker
		subnetCIDR := fmt.Sprintf("%s/%d", nwCfg.SubnetIP, nwCfg.SubnetLen)
		err = createDockNet(tenantName, network.Name, "", subnetCIDR, nwCfg.Gateway)
		if err != nil {
			log.Errorf("Error creating network %s in docker. Err: %v", nwCfg.ID, err)
			return err
		}

		// 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
}