Skip to content

Commit

Permalink
fix subnet available IPs
Browse files Browse the repository at this point in the history
  • Loading branch information
zhangzujian committed Jul 14, 2021
1 parent b607602 commit 22a296e
Show file tree
Hide file tree
Showing 7 changed files with 203 additions and 57 deletions.
6 changes: 3 additions & 3 deletions pkg/controller/subnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -1051,11 +1051,11 @@ func calcDualSubnetStatusIP(subnet *kubeovnv1.Subnet, c *Controller) error {
v6UsingIPs = append(v6UsingIPs, splitIPs[1])
}
}
v4availableIPs := util.AddressCount(v4CIDR) - float64(util.CountIpNums(v4toSubIPs))
v4availableIPs := util.AddressCount(v4CIDR) - util.CountIpNums(v4toSubIPs)
if v4availableIPs < 0 {
v4availableIPs = 0
}
v6availableIPs := util.AddressCount(v6CIDR) - float64(util.CountIpNums(v6toSubIPs))
v6availableIPs := util.AddressCount(v6CIDR) - util.CountIpNums(v6toSubIPs)
if v6availableIPs < 0 {
v6availableIPs = 0
}
Expand Down Expand Up @@ -1091,7 +1091,7 @@ func calcSubnetStatusIP(subnet *kubeovnv1.Subnet, c *Controller) error {
for _, podUsedIP := range podUsedIPs.Items {
toSubIPs = append(toSubIPs, podUsedIP.Spec.IPAddress)
}
availableIPs := util.AddressCount(cidr) - float64(util.CountIpNums(toSubIPs))
availableIPs := util.AddressCount(cidr) - util.CountIpNums(toSubIPs)
if availableIPs < 0 {
availableIPs = 0
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/ipam/ipam.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ func (ipam *IPAM) AddOrUpdateSubnet(name, cidrStr string, excludeIps []string) e
_, cidr, _ := net.ParseCIDR(v4cidrStr)
subnet.V4CIDR = cidr
subnet.V4ReservedIPList = convertExcludeIps(v4ExcludeIps)
firstIP, _ := util.FirstSubnetIP(v4cidrStr)
firstIP, _ := util.FirstIP(v4cidrStr)
lastIP, _ := util.LastIP(v4cidrStr)
subnet.V4FreeIPList = IPRangeList{&IPRange{Start: IP(firstIP), End: IP(lastIP)}}
subnet.joinFreeWithReserve()
Expand All @@ -163,7 +163,7 @@ func (ipam *IPAM) AddOrUpdateSubnet(name, cidrStr string, excludeIps []string) e
_, cidr, _ := net.ParseCIDR(v6cidrStr)
subnet.V6CIDR = cidr
subnet.V6ReservedIPList = convertExcludeIps(v6ExcludeIps)
firstIP, _ := util.FirstSubnetIP(v6cidrStr)
firstIP, _ := util.FirstIP(v6cidrStr)
lastIP, _ := util.LastIP(v6cidrStr)
subnet.V6FreeIPList = IPRangeList{&IPRange{Start: IP(firstIP), End: IP(lastIP)}}
subnet.joinFreeWithReserve()
Expand Down
8 changes: 4 additions & 4 deletions pkg/ipam/subnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func NewSubnet(name, cidrStr string, excludeIps []string) (*Subnet, error) {
subnet := Subnet{}
protocol := util.CheckProtocol(cidrStr)
if protocol == kubeovnv1.ProtocolIPv4 {
firstIP, _ := util.FirstSubnetIP(cidrStr)
firstIP, _ := util.FirstIP(cidrStr)
lastIP, _ := util.LastIP(cidrStr)

subnet = Subnet{
Expand All @@ -66,7 +66,7 @@ func NewSubnet(name, cidrStr string, excludeIps []string) (*Subnet, error) {
}
subnet.joinFreeWithReserve()
} else if protocol == kubeovnv1.ProtocolIPv6 {
firstIP, _ := util.FirstSubnetIP(cidrStr)
firstIP, _ := util.FirstIP(cidrStr)
lastIP, _ := util.LastIP(cidrStr)

subnet = Subnet{
Expand All @@ -87,9 +87,9 @@ func NewSubnet(name, cidrStr string, excludeIps []string) (*Subnet, error) {
subnet.joinFreeWithReserve()
} else {
cidrBlocks := strings.Split(cidrStr, ",")
v4FirstIP, _ := util.FirstSubnetIP(cidrBlocks[0])
v4FirstIP, _ := util.FirstIP(cidrBlocks[0])
v4LastIP, _ := util.LastIP(cidrBlocks[0])
v6FirstIP, _ := util.FirstSubnetIP(cidrBlocks[1])
v6FirstIP, _ := util.FirstIP(cidrBlocks[1])
v6LastIP, _ := util.LastIP(cidrBlocks[1])

subnet = Subnet{
Expand Down
93 changes: 46 additions & 47 deletions pkg/util/net.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func SubnetNumber(subnet string) string {
return cidr.IP.String()
}

func SubnetBroadCast(subnet string) string {
func SubnetBroadcast(subnet string) string {
_, cidr, _ := net.ParseCIDR(subnet)
var length uint
if CheckProtocol(subnet) == kubeovnv1.ProtocolIPv4 {
Expand All @@ -68,7 +68,7 @@ func SubnetBroadCast(subnet string) string {
return BigInt2Ip(ipInt.Add(ipInt, size))
}

func FirstSubnetIP(subnet string) (string, error) {
func FirstIP(subnet string) (string, error) {
_, cidr, err := net.ParseCIDR(subnet)
if err != nil {
return "", fmt.Errorf("%s is not a valid cidr", subnet)
Expand Down Expand Up @@ -225,7 +225,7 @@ func CheckCidrs(cidr string) error {
func GetGwByCidr(cidrStr string) (string, error) {
var gws []string
for _, cidr := range strings.Split(cidrStr, ",") {
gw, err := FirstSubnetIP(cidr)
gw, err := FirstIP(cidr)
if err != nil {
return "", err
}
Expand All @@ -242,7 +242,7 @@ func AppendGwByCidr(gateway, cidrStr string) (string, error) {
gws = append(gws, gateway)
continue
} else {
gw, err := FirstSubnetIP(cidr)
gw, err := FirstIP(cidr)
if err != nil {
return "", err
}
Expand Down Expand Up @@ -336,54 +336,52 @@ func ExpandExcludeIPs(excludeIPs []string, cidr string) []string {
rv := []string{}
for _, excludeIP := range excludeIPs {
if strings.Contains(excludeIP, "..") {
parts := strings.Split(excludeIP, "..")
if len(parts) != 2 || CheckProtocol(parts[0]) != CheckProtocol(parts[1]) {
klog.Errorf("invalid exlcude IP: %s", excludeIP)
continue
}
s := Ip2BigInt(parts[0])
e := Ip2BigInt(parts[1])
if s.Cmp(e) > 0 {
continue
}

for _, cidrBlock := range strings.Split(cidr, ",") {
subnetNum := SubnetNumber(cidrBlock)
broadcast := SubnetBroadCast(cidrBlock)
parts := strings.Split(excludeIP, "..")
s := Ip2BigInt(parts[0])
e := Ip2BigInt(parts[1])

// limit range in cidr
firstIP, _ := FirstSubnetIP(cidrBlock)
lastIP, _ := LastIP(cidrBlock)
if s.Cmp(Ip2BigInt(firstIP)) < 0 {
s = Ip2BigInt(firstIP)
}
if e.Cmp(Ip2BigInt(lastIP)) > 0 {
e = Ip2BigInt(lastIP)
if CheckProtocol(cidrBlock) != CheckProtocol(parts[0]) {
continue
}

changed := false
// exclude cidr and broadcast address
if ContainsIPs(excludeIP, subnetNum) {
v := Ip2BigInt(subnetNum)
if s.Cmp(v) == 0 {
s.Add(s, big.NewInt(1))
rv = append(rv, BigInt2Ip(s)+".."+BigInt2Ip(e))
} else if e.Cmp(v) == 0 {
e.Sub(e, big.NewInt(1))
rv = append(rv, BigInt2Ip(s)+".."+BigInt2Ip(e))
} else {
var low, high big.Int
lowp := (&low).Sub(v, big.NewInt(1))
highp := (&high).Add(v, big.NewInt(1))
rv = append(rv, BigInt2Ip(s)+".."+BigInt2Ip(lowp))
rv = append(rv, BigInt2Ip(highp)+".."+BigInt2Ip(e))
}
changed = true
firstIP, err := FirstIP(cidrBlock)
if err != nil {
klog.Error(err)
continue
}
if firstIP == SubnetBroadcast(cidrBlock) {
klog.Errorf("no available IP address in CIDR %s", cidrBlock)
continue
}
lastIP, _ := LastIP(cidrBlock)
s1, e1 := s, e
if s1.Cmp(Ip2BigInt(firstIP)) < 0 {
s1 = Ip2BigInt(firstIP)
}
if ContainsIPs(excludeIP, broadcast) {
v := Ip2BigInt(broadcast)
v.Sub(v, big.NewInt(1))
rv = append(rv, BigInt2Ip(s)+".."+BigInt2Ip(v))
changed = true
if e1.Cmp(Ip2BigInt(lastIP)) > 0 {
e1 = Ip2BigInt(lastIP)
}
if !changed && s.Cmp(e) < 0 {
rv = append(rv, BigInt2Ip(s)+".."+BigInt2Ip(e))
if c := s1.Cmp(e1); c == 0 {
rv = append(rv, BigInt2Ip(s1))
} else if c < 0 {
rv = append(rv, BigInt2Ip(s1)+".."+BigInt2Ip(e1))
}
}
} else {
rv = append(rv, excludeIP)
for _, cidrBlock := range strings.Split(cidr, ",") {
if CIDRContainIP(cidrBlock, excludeIP) && excludeIP != SubnetNumber(cidrBlock) && excludeIP != SubnetBroadcast(cidrBlock) {
rv = append(rv, excludeIP)
break
}
}
}
}
klog.V(3).Infof("expand exclude ips %v", rv)
Expand All @@ -407,15 +405,16 @@ func ContainsIPs(excludeIP string, ip string) bool {
return false
}

func CountIpNums(excludeIPs []string) int64 {
var count int64
func CountIpNums(excludeIPs []string) float64 {
var count float64
for _, excludeIP := range excludeIPs {
if strings.Contains(excludeIP, "..") {
var val big.Int
parts := strings.Split(excludeIP, "..")
s := Ip2BigInt(parts[0])
e := Ip2BigInt(parts[1])
count = val.Add(val.Sub(e, s), big.NewInt(1)).Int64()
v, _ := new(big.Float).SetInt(val.Add(val.Sub(e, s), big.NewInt(1))).Float64()
count += v
} else {
count++
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/util/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ func ValidatePodCidr(cidr, ip string) error {
}

ipStr := IPToString(ipAddr)
if SubnetBroadCast(cidrBlock) == ipStr {
if SubnetBroadcast(cidrBlock) == ipStr {
return fmt.Errorf("%s is the broadcast ip in cidr %s", ipStr, cidrBlock)
}
if SubnetNumber(cidrBlock) == ipStr {
Expand Down
1 change: 1 addition & 0 deletions test/unittest/unit_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

// tests to run
_ "github.com/kubeovn/kube-ovn/test/unittest/ipam"
_ "github.com/kubeovn/kube-ovn/test/unittest/util"
)

func TestE2e(t *testing.T) {
Expand Down
146 changes: 146 additions & 0 deletions test/unittest/util/net.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package util

import (
"net"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"

"github.com/kubeovn/kube-ovn/pkg/util"
)

var _ = Describe("[Net]", func() {
It("AddressCount", func() {
args := []*net.IPNet{
{IP: net.ParseIP("10.0.0.0"), Mask: net.CIDRMask(32, 32)},
{IP: net.ParseIP("10.0.0.0"), Mask: net.CIDRMask(31, 32)},
{IP: net.ParseIP("10.0.0.0"), Mask: net.CIDRMask(30, 32)},
{IP: net.ParseIP("10.0.0.0"), Mask: net.CIDRMask(24, 32)},
}
wants := []float64{
0,
0,
2,
254,
}
Expect(len(args)).To(Equal(len(args)))

for i := range args {
Expect(args[i].IP).NotTo(BeNil())
Expect(util.AddressCount(args[i])).To(Equal(wants[i]))
}
})

It("CountIpNums", func() {
args := [][]string{
{"10.0.0.101"},
{"10.0.0.101..10.0.0.105"},
{"10.0.0.101..10.0.0.105", "10.0.0.111..10.0.0.120"},
}
wants := []float64{
1,
5,
15,
}
Expect(len(args)).To(Equal(len(args)))

for i := range args {
Expect(util.CountIpNums(args[i])).To(Equal(wants[i]))
}
})

It("ExpandExcludeIPs", func() {
type arg struct {
cidr string
excludeIps []string
}

args := []arg{
{"10.0.1.0/24", []string{"10.0.0.255"}},
{"10.0.1.0/24", []string{"10.0.1.0"}},
{"10.0.1.0/24", []string{"10.0.1.1"}},
{"10.0.1.0/24", []string{"10.0.1.254"}},
{"10.0.1.0/24", []string{"10.0.1.255"}},
{"10.0.1.0/24", []string{"10.0.2.0"}},
{"10.0.1.0/24", []string{"10.0.1.101..10.0.1.105"}},
{"10.0.1.0/24", []string{"10.0.0.101..10.0.1.105"}},
{"10.0.1.0/24", []string{"10.0.1.101..10.0.2.105"}},
{"10.0.1.0/24", []string{"10.0.1.101..10.0.1.101"}},
{"10.0.1.0/24", []string{"10.0.1.105..10.0.1.101"}},
{"10.0.1.0/24", []string{"10.0.1.1", "10.0.1.101"}},
{"10.0.1.0/24", []string{"10.0.1.1", "10.0.1.101..10.0.1.105"}},
{"10.0.1.0/24", []string{"10.0.1.1", "10.0.1.101..10.0.1.105", "10.0.1.111..10.0.1.120"}},
{"10.0.1.0/30", []string{"10.0.1.1", "179.17.0.0..179.17.0.10"}},
{"10.0.1.0/31", []string{"10.0.1.1", "179.17.0.0..179.17.0.10"}},
{"10.0.1.0/32", []string{"10.0.1.1", "179.17.0.0..179.17.0.10"}},

{"fe00::100/120", []string{"fe00::ff"}},
{"fe00::100/120", []string{"fe00::100"}},
{"fe00::100/120", []string{"fe00::101"}},
{"fe00::100/120", []string{"fe00::1fe"}},
{"fe00::100/120", []string{"fe00::1ff"}},
{"fe00::100/120", []string{"fe00::200"}},
{"fe00::100/120", []string{"fe00::1a1..fe00::1a5"}},
{"fe00::100/120", []string{"fe00::a1..fe00::1a5"}},
{"fe00::100/120", []string{"fe00::1a1..fe00::2a5"}},
{"fe00::100/120", []string{"fe00::1a1..fe00::1a1"}},
{"fe00::100/120", []string{"fe00::1a5..fe00::1a1"}},
{"fe00::100/120", []string{"fe00::101", "fe00::1a1"}},
{"fe00::100/120", []string{"fe00::101", "fe00::1a1..fe00::1a5"}},
{"fe00::100/120", []string{"fe00::101", "fe00::1a1..fe00::1a5", "fe00::1b1..fe00::1c0"}},
{"fe00::100/126", []string{"fe00::101", "feff::..feff::a"}},
{"fe00::100/127", []string{"fe00::101", "feff::..feff::a"}},
{"fe00::100/128", []string{"fe00::101", "feff::..feff::a"}},

{"10.0.1.0/24,fe00::100/120", []string{"10.0.1.1", "10.0.1.101..10.0.1.105"}},
{"10.0.1.0/24,fe00::100/120", []string{"fe00::101", "fe00::1a1..fe00::1a5"}},
{"10.0.1.0/24,fe00::100/120", []string{"10.0.1.1", "10.0.1.101..10.0.1.105", "fe00::101", "fe00::1a1..fe00::1a5"}},
}
wants := [][]string{
{},
{},
{"10.0.1.1"},
{"10.0.1.254"},
{},
{},
{"10.0.1.101..10.0.1.105"},
{"10.0.1.1..10.0.1.105"},
{"10.0.1.101..10.0.1.254"},
{"10.0.1.101"},
{},
{"10.0.1.1", "10.0.1.101"},
{"10.0.1.1", "10.0.1.101..10.0.1.105"},
{"10.0.1.1", "10.0.1.101..10.0.1.105", "10.0.1.111..10.0.1.120"},
{"10.0.1.1"},
{},
{},

{},
{},
{"fe00::101"},
{"fe00::1fe"},
{},
{},
{"fe00::1a1..fe00::1a5"},
{"fe00::101..fe00::1a5"},
{"fe00::1a1..fe00::1fe"},
{"fe00::1a1"},
{},
{"fe00::101", "fe00::1a1"},
{"fe00::101", "fe00::1a1..fe00::1a5"},
{"fe00::101", "fe00::1a1..fe00::1a5", "fe00::1b1..fe00::1c0"},
{"fe00::101"},
{},
{},

{"10.0.1.1", "10.0.1.101..10.0.1.105"},
{"fe00::101", "fe00::1a1..fe00::1a5"},
{"10.0.1.1", "10.0.1.101..10.0.1.105", "fe00::101", "fe00::1a1..fe00::1a5"},
}
Expect(len(args)).To(Equal(len(args)))

for i := range args {
Expect(util.ExpandExcludeIPs(args[i].excludeIps, args[i].cidr)).To(Equal(wants[i]))
}
})
})

0 comments on commit 22a296e

Please sign in to comment.