Skip to content

Commit

Permalink
IPPool: fix missing support for CIDR (#2982)
Browse files Browse the repository at this point in the history
  • Loading branch information
zhangzujian committed Jun 30, 2023
1 parent f2d063a commit 5c45549
Show file tree
Hide file tree
Showing 19 changed files with 472 additions and 158 deletions.
2 changes: 1 addition & 1 deletion Makefile.e2e
Expand Up @@ -110,7 +110,7 @@ kube-ovn-conformance-e2e:
E2E_BRANCH=$(E2E_BRANCH) \
E2E_IP_FAMILY=$(E2E_IP_FAMILY) \
E2E_NETWORK_MODE=$(E2E_NETWORK_MODE) \
ginkgo $(GINKGO_PARALLEL_OPT) --randomize-all -v \
ginkgo $(GINKGO_PARALLEL_OPT) --randomize-all -v --timeout=25m \
--focus=CNI:Kube-OVN ./test/e2e/kube-ovn/kube-ovn.test

.PHONY: kube-ovn-ic-conformance-e2e
Expand Down
13 changes: 13 additions & 0 deletions pkg/controller/subnet.go
Expand Up @@ -823,6 +823,19 @@ func (c *Controller) handleAddOrUpdateSubnet(key string) error {
}

c.updateVpcStatusQueue.Add(subnet.Spec.Vpc)

ippools, err := c.ippoolLister.List(labels.Everything())
if err != nil {
klog.Errorf("failed to list ippools: %v", err)
return err
}

for _, p := range ippools {
if p.Spec.Subnet == subnet.Name {
c.addOrUpdateIPPoolQueue.Add(p.Name)
}
}

return nil
}

Expand Down
31 changes: 16 additions & 15 deletions pkg/ipam/ip.go
Expand Up @@ -22,6 +22,12 @@ func NewIP(s string) (IP, error) {
return IP(ip), nil
}

func (a IP) Clone() IP {
v := make(IP, len(a))
copy(v, a)
return v
}

func (a IP) To4() net.IP {
return net.IP(a).To4()
}
Expand All @@ -42,28 +48,23 @@ func (a IP) GreaterThan(b IP) bool {
return big.NewInt(0).SetBytes([]byte(a)).Cmp(big.NewInt(0).SetBytes([]byte(b))) > 0
}

func (a IP) Add(n int64) IP {
buff := big.NewInt(0).Add(big.NewInt(0).SetBytes([]byte(a)), big.NewInt(n)).Bytes()
if len(buff) < len(a) {
tmp := make([]byte, len(a))
func bytes2IP(buff []byte, length int) IP {
if len(buff) < length {
tmp := make([]byte, length)
copy(tmp[len(tmp)-len(buff):], buff)
buff = tmp
} else if len(buff) > len(a) {
buff = buff[len(buff)-len(a):]
} else if len(buff) > length {
buff = buff[len(buff)-length:]
}
return IP(buff)
}

func (a IP) Add(n int64) IP {
return bytes2IP(big.NewInt(0).Add(big.NewInt(0).SetBytes([]byte(a)), big.NewInt(n)).Bytes(), len(a))
}

func (a IP) Sub(n int64) IP {
buff := big.NewInt(0).Sub(big.NewInt(0).SetBytes([]byte(a)), big.NewInt(n)).Bytes()
if len(buff) < len(a) {
tmp := make([]byte, len(a))
copy(tmp[len(tmp)-len(buff):], buff)
buff = tmp
} else if len(buff) > len(a) {
buff = buff[len(buff)-len(a):]
}
return IP(buff)
return bytes2IP(big.NewInt(0).Sub(big.NewInt(0).SetBytes([]byte(a)), big.NewInt(n)).Bytes(), len(a))
}

func (a IP) String() string {
Expand Down
21 changes: 20 additions & 1 deletion pkg/ipam/ip_range.go
@@ -1,8 +1,10 @@
package ipam

import (
"crypto/rand"
"fmt"
"math/big"
"net"

"github.com/kubeovn/kube-ovn/pkg/internal"
)
Expand All @@ -16,8 +18,18 @@ func NewIPRange(start, end IP) *IPRange {
return &IPRange{start, end}
}

func NewIPRangeFromCIDR(cidr net.IPNet) *IPRange {
start, _ := NewIP(cidr.IP.Mask(cidr.Mask).String())
end := make(IP, len(start))
for i := 0; i < len(end); i++ {
end[i] = start[i] | ^cidr.Mask[i]
}

return &IPRange{start, end}
}

func (r *IPRange) Clone() *IPRange {
return NewIPRange(r.start, r.end)
return NewIPRange(r.start.Clone(), r.end.Clone())
}

func (r *IPRange) Start() IP {
Expand All @@ -41,6 +53,13 @@ func (r *IPRange) Count() internal.BigInt {
return internal.BigInt{Int: *n.Add(n, big.NewInt(1))}
}

func (r *IPRange) Random() IP {
x := big.NewInt(0).SetBytes([]byte(r.start))
y := big.NewInt(0).SetBytes([]byte(r.end))
n, _ := rand.Int(rand.Reader, big.NewInt(0).Add(big.NewInt(0).Sub(y, x), big.NewInt(1)))
return bytes2IP(big.NewInt(0).Add(x, n).Bytes(), len(r.start))
}

func (r *IPRange) Contains(ip IP) bool {
return !r.start.GreaterThan(ip) && !r.end.LessThan(ip)
}
Expand Down
32 changes: 24 additions & 8 deletions pkg/ipam/ip_range_list.go
Expand Up @@ -2,6 +2,7 @@ package ipam

import (
"fmt"
"net"
"sort"
"strings"

Expand Down Expand Up @@ -31,21 +32,32 @@ func NewIPRangeList(ips ...IP) (*IPRangeList, error) {
func NewIPRangeListFrom(x ...string) (*IPRangeList, error) {
ret := &IPRangeList{}
for _, s := range x {
ips := strings.Split(s, "..")
start, err := NewIP(ips[0])
if err != nil {
return nil, err
}
var r *IPRange
if len(ips) == 1 {
r = NewIPRange(start, start)
} else {
if strings.Contains(s, "..") {
ips := strings.Split(s, "..")
start, err := NewIP(ips[0])
if err != nil {
return nil, err
}
end, err := NewIP(ips[1])
if err != nil {
return nil, err
}
r = NewIPRange(start, end)
} else if strings.ContainsRune(s, '/') {
_, cidr, err := net.ParseCIDR(s)
if err != nil {
return nil, err
}
r = NewIPRangeFromCIDR(*cidr)
} else {
start, err := NewIP(s)
if err != nil {
return nil, err
}
r = NewIPRange(start, start.Clone())
}

ret = ret.Merge(&IPRangeList{[]*IPRange{r}})
}
return ret, nil
Expand Down Expand Up @@ -256,6 +268,10 @@ func (r *IPRangeList) Merge(x *IPRangeList) *IPRangeList {
return ret.Clone()
}

func (r *IPRangeList) MergeRange(x *IPRange) *IPRangeList {
return r.Merge(&IPRangeList{ranges: []*IPRange{x}}).Clone()
}

// Intersect returns a new list which contains items which are in both `r` and `x`
func (r *IPRangeList) Intersect(x *IPRangeList) *IPRangeList {
r1, r2 := r.Separate(x), x.Separate(r)
Expand Down
2 changes: 1 addition & 1 deletion pkg/util/net.go
Expand Up @@ -274,7 +274,7 @@ func SplitIpsByProtocol(excludeIps []string) ([]string, []string) {
var v4ExcludeIps, v6ExcludeIps []string
for _, ex := range excludeIps {
ips := strings.Split(ex, "..")
if net.ParseIP(ips[0]).To4() != nil {
if CheckProtocol(ips[0]) == kubeovnv1.ProtocolIPv4 {
v4ExcludeIps = append(v4ExcludeIps, ex)
} else {
v6ExcludeIps = append(v6ExcludeIps, ex)
Expand Down
10 changes: 10 additions & 0 deletions test/e2e/framework/expect.go
Expand Up @@ -98,6 +98,16 @@ func ExpectNotContainElement(actual interface{}, extra interface{}, explain ...i
gomega.ExpectWithOffset(1, actual).NotTo(gomega.ContainElement(extra), explain...)
}

// ExpectContainSubstring expects actual contains the passed-in substring.
func ExpectContainSubstring(actual, substr string, explain ...interface{}) {
gomega.ExpectWithOffset(1, actual).To(gomega.ContainSubstring(substr), explain...)
}

// ExpectNotContainSubstring expects actual does not contain the passed-in substring.
func ExpectNotContainSubstring(actual, substr string, explain ...interface{}) {
gomega.ExpectWithOffset(1, actual).NotTo(gomega.ContainSubstring(substr), explain...)
}

// ExpectHaveKey expects the actual map has the key in the keyset
func ExpectHaveKey(actual interface{}, key interface{}, explain ...interface{}) {
gomega.ExpectWithOffset(1, actual).To(gomega.HaveKey(key), explain...)
Expand Down
26 changes: 24 additions & 2 deletions test/e2e/framework/framework.go
Expand Up @@ -16,6 +16,12 @@ import (
kubeovncs "github.com/kubeovn/kube-ovn/pkg/client/clientset/versioned"
)

const (
IPv4 = "ipv4"
IPv6 = "ipv6"
Dual = "dual"
)

const (
// poll is how often to Poll resources.
poll = 2 * time.Second
Expand Down Expand Up @@ -103,8 +109,24 @@ func NewFrameworkWithContext(baseName, kubeContext string) *Framework {
return f
}

func (f *Framework) IPv6() bool {
return f.ClusterIpFamily == "ipv6"
func (f *Framework) IsIPv4() bool {
return f.ClusterIpFamily == IPv4
}

func (f *Framework) IsIPv6() bool {
return f.ClusterIpFamily == IPv6
}

func (f *Framework) IsDual() bool {
return f.ClusterIpFamily == Dual
}

func (f *Framework) HasIPv4() bool {
return !f.IsIPv6()
}

func (f *Framework) HasIPv6() bool {
return !f.IsIPv4()
}

// BeforeEach gets a kube-ovn client
Expand Down

0 comments on commit 5c45549

Please sign in to comment.