diff --git a/netmaster/master/network.go b/netmaster/master/network.go index 895bce609..9fa1d82f2 100755 --- a/netmaster/master/network.go +++ b/netmaster/master/network.go @@ -363,7 +363,7 @@ func networkAllocAddress(nwCfg *mastercfg.CfgNetworkState, epgCfg *mastercfg.End } else { if epgCfg != nil && len(epgCfg.IPPool) > 0 { // allocate from epg network log.Infof("allocating ip address from epg pool %s", epgCfg.IPPool) - ipAddrValue, found = epgCfg.EPGIPAllocMap.NextClear(0) + ipAddrValue, found = netutils.NextClear(epgCfg.EPGIPAllocMap, 0, nwCfg.SubnetLen) if !found { log.Errorf("auto allocation failed - address exhaustion in pool %s", epgCfg.IPPool) @@ -378,7 +378,7 @@ func networkAllocAddress(nwCfg *mastercfg.CfgNetworkState, epgCfg *mastercfg.End } epgCfg.EPGIPAllocMap.Set(ipAddrValue) } else { - ipAddrValue, found = nwCfg.IPAllocMap.NextClear(0) + ipAddrValue, found = netutils.NextClear(nwCfg.IPAllocMap, 0, nwCfg.SubnetLen) if !found { log.Errorf("auto allocation failed - address exhaustion in subnet %s/%d", nwCfg.SubnetIP, nwCfg.SubnetLen) diff --git a/test/integration/endpoint_test.go b/test/integration/endpoint_test.go index 8bf8db606..24cafe1d9 100644 --- a/test/integration/endpoint_test.go +++ b/test/integration/endpoint_test.go @@ -217,6 +217,61 @@ func (its *integTestSuite) TestEndpointGroupCreateDelete(c *C) { } assertNoErr(its.client.NetworkDelete("default", "test"), c, "deleting network") + + // test network/epg subnet + nwData := []struct { + subnet string + availableIP string + }{ + + {subnet: "10.100.100.194-10.100.100.222/27", availableIP: "10.100.100.194-10.100.100.222"}, + {subnet: "10.1.1.5-10.1.1.15/27", availableIP: "10.1.1.5-10.1.1.15"}, + {subnet: "10.1.1.0/27", availableIP: "10.1.1.1-10.1.1.30"}, + {subnet: "10.1.1.0/28", availableIP: "10.1.1.1-10.1.1.14"}, + {subnet: "10.1.1.0/29", availableIP: "10.1.1.1-10.1.1.6"}, + {subnet: "10.1.1.0/30", availableIP: "10.1.1.1-10.1.1.2"}, + {subnet: "10.1.1.0/31"}, + } + for _, nwRange := range nwData { + err := its.client.NetworkPost(&client.Network{ + TenantName: "default", + NetworkName: "subnet-test1", + Subnet: nwRange.subnet, + Encap: its.encap, + }) + assertNoErr(err, c, "creating network") + + // inspect + nInspect, err := its.client.NetworkInspect("default", "subnet-test1") + assertNoErr(err, c, fmt.Sprintf("inspect failed for %+v", nwRange.subnet)) + assertOnTrue(c, nInspect.Oper.AllocatedIPAddresses != "", + fmt.Sprintf("invalid allocated address %+v", nInspect)) + assertOnTrue(c, nInspect.Oper.AvailableIPAddresses != nwRange.availableIP, + fmt.Sprintf("invalid available address %+v", nInspect)) + + + // check epg + err = its.client.EndpointGroupPost(&client.EndpointGroup{ + TenantName: "default", + NetworkName: "subnet-test1", + GroupName: "epg1", + IpPool: nwRange.availableIP, + Policies: []string{}, + ExtContractsGrps: []string{}, + }) + assertNoErr(err, c, fmt.Sprintf("create epg %+v", "epg1")) + // inspect + dInspect, e := its.client.EndpointGroupInspect("default", "epg1") + assertNoErr(e, c, fmt.Sprintf("inspect failed for %+v", nwRange)) + assertOnTrue(c, dInspect.Oper.AllocatedIPAddresses != "", + fmt.Sprintf("invalid allocated address %+v", dInspect)) + assertOnTrue(c, dInspect.Oper.AvailableIPAddresses != nwRange.availableIP, + fmt.Sprintf("invalid available address %+v", dInspect)) + assertNoErr(its.client.EndpointGroupDelete("default", "epg1"), c, "delete epg") + + assertNoErr(its.client.NetworkDelete("default", "subnet-test1"), c, "deleting network") + } + } // TestEndpointGrouIPPoolCreateDelete tests EPG with IPAM create delete ops diff --git a/utils/netutils/netutils.go b/utils/netutils/netutils.go index 37b6fb052..5da8f8417 100644 --- a/utils/netutils/netutils.go +++ b/utils/netutils/netutils.go @@ -994,6 +994,17 @@ func ListAllocatedIPs(allocMap bitset.BitSet, ipPool string, subnetIP string, su return strings.Join(list, ", ") } +// NextClear wrapper around Bitset to check max id +func NextClear(allocMap bitset.BitSet, idx uint, subnetLen uint) (uint, bool) { + maxHosts := uint(1 << (32 - subnetLen)) + + value, found := allocMap.NextClear(idx) + if found && value >= maxHosts { + return 0, false + } + return value, found +} + // ListAvailableIPs returns a string of available IPs in a network func ListAvailableIPs(allocMap bitset.BitSet, subnetIP string, subnetLen uint) string { idx := uint(0) @@ -1002,7 +1013,7 @@ func ListAvailableIPs(allocMap bitset.BitSet, subnetIP string, subnetLen uint) s inRange := false for { - foundValue, found := allocMap.NextClear(idx) + foundValue, found := NextClear(allocMap, idx, subnetLen) if !found { break }