@@ -3,19 +3,20 @@ package ipalloc
33import (
44 "context"
55 "fmt"
6+ "net"
7+ "sync"
8+
9+ ipallocator "github.com/ovn-org/ovn-kubernetes/go-controller/pkg/allocator/ip"
610 "github.com/ovn-org/ovn-kubernetes/go-controller/pkg/util"
7- corev1 "k8s.io/api/core/v1"
811 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
912 v1 "k8s.io/client-go/kubernetes/typed/core/v1"
10- "net"
11- "sync"
1213)
1314
1415// primaryIPAllocator attempts to allocate an IP in the same subnet as a nodes primary network
1516type primaryIPAllocator struct {
1617 mu * sync.Mutex
17- v4 * ipAllocator
18- v6 * ipAllocator
18+ v4 * ipallocator. Range
19+ v6 * ipallocator. Range
1920 nodeClient v1.NodeInterface
2021}
2122
@@ -47,91 +48,37 @@ func newPrimaryIPAllocator(nodeClient v1.NodeInterface) (*primaryIPAllocator, er
4748 if len (nodes .Items ) == 0 {
4849 return ipa , fmt .Errorf ("expected at least one node but found zero" )
4950 }
50- // FIXME: the approach taken here to find the first node IP+mask and then to increment the second last octet wont work in
51- // all scenarios (node with /24). We should generate an EgressIP compatible with a Node providers primary network and then take care its unique globally.
5251
53- // The approach here is to grab initial starting IP from first node found, increment the second last octet.
54- // Approach taken here won't work for Nodes handed /24 subnets.
55- nodePrimaryIPs , err := util .ParseNodePrimaryIfAddr (& nodes .Items [0 ])
56- if err != nil {
57- return ipa , fmt .Errorf ("failed to parse node primary interface address from Node object: %v" , err )
58- }
59- if nodePrimaryIPs .V4 .IP != nil {
60- // should be ok with /16 and /64 node primary provider subnets
61- // TODO; fixme; what about /24 subnet Nodes like GCP
62- nodePrimaryIPs .V4 .IP [len (nodePrimaryIPs .V4 .IP )- 2 ]++
63- ipa .v4 = newIPAllocator (& net.IPNet {IP : nodePrimaryIPs .V4 .IP , Mask : nodePrimaryIPs .V4 .Net .Mask })
64- }
65- if nodePrimaryIPs .V6 .IP != nil {
66- nodePrimaryIPs .V6 .IP [len (nodePrimaryIPs .V6 .IP )- 2 ]++
67- ipa .v6 = newIPAllocator (& net.IPNet {IP : nodePrimaryIPs .V6 .IP , Mask : nodePrimaryIPs .V6 .Net .Mask })
68- }
69- // verify the new starting base IP is within all Nodes subnets
70- if nodePrimaryIPs .V4 .IP != nil {
71- ipNets , err := getNodePrimaryProviderIPs (nodes .Items , false )
72- if err != nil {
73- return ipa , err
74- }
75- nextIP , err := ipa .v4 .AllocateNextIP ()
76- if err != nil {
77- return ipa , err
78- }
79- if ! isIPWithinAllSubnets (ipNets , nextIP ) {
80- return ipa , fmt .Errorf ("IP %s is not within all Node subnets" , nextIP )
81- }
82- }
83- if nodePrimaryIPs .V6 .IP != nil {
84- ipNets , err := getNodePrimaryProviderIPs (nodes .Items , true )
85- if err != nil {
86- return ipa , err
87- }
88- nextIP , err := ipa .v6 .AllocateNextIP ()
89- if err != nil {
90- return ipa , err
91- }
92- if ! isIPWithinAllSubnets (ipNets , nextIP ) {
93- return ipa , fmt .Errorf ("IP %s is not within all Node subnets" , nextIP )
94- }
95- }
96-
97- return ipa , nil
98- }
99-
100- func getNodePrimaryProviderIPs (nodes []corev1.Node , isIPv6 bool ) ([]* net.IPNet , error ) {
101- ipNets := make ([]* net.IPNet , 0 , len (nodes ))
102- for _ , node := range nodes {
52+ for _ , node := range nodes .Items {
10353 nodePrimaryIPs , err := util .ParseNodePrimaryIfAddr (& node )
10454 if err != nil {
105- return nil , fmt .Errorf ("failed to parse node primary interface address from Node %s object: %v" , node .Name , err )
55+ return ipa , fmt .Errorf ("failed to parse node primary interface address from Node %s object: %v" , node .Name , err )
56+ }
57+ if nodePrimaryIPs .V4 .IP != nil {
58+ if ipa .v4 == nil {
59+ ipa .v4 , err = ipallocator .NewCIDRRange (nodePrimaryIPs .V4 .Net )
60+ if err != nil {
61+ return ipa , fmt .Errorf ("failed to create new CIDR range for IPv4: %v" , err )
62+ }
63+ }
64+ if err := ipa .v4 .Allocate (nodePrimaryIPs .V4 .IP ); err != nil {
65+ return ipa , fmt .Errorf ("failed to allocate IPv4 %s: %v" , nodePrimaryIPs .V4 .IP , err )
66+ }
67+ }
68+ if nodePrimaryIPs .V6 .IP != nil {
69+ if ipa .v6 == nil {
70+ ipa .v6 , err = ipallocator .NewCIDRRange (nodePrimaryIPs .V6 .Net )
71+ if err != nil {
72+ return ipa , fmt .Errorf ("failed to create new CIDR range for IPv6: %v" , err )
73+ }
74+ }
75+ if err := ipa .v6 .Allocate (nodePrimaryIPs .V6 .IP ); err != nil {
76+ return ipa , fmt .Errorf ("failed to allocate IPv6 %s: %v" , nodePrimaryIPs .V6 .IP , err )
77+ }
10678 }
107- var mask net.IPMask
108- var ip net.IP
10979
110- if isIPv6 {
111- ip = nodePrimaryIPs .V6 .IP
112- mask = nodePrimaryIPs .V6 .Net .Mask
113- } else {
114- ip = nodePrimaryIPs .V4 .IP
115- mask = nodePrimaryIPs .V4 .Net .Mask
116- }
117- if len (ip ) == 0 || len (mask ) == 0 {
118- return nil , fmt .Errorf ("failed to find Node %s primary Node IP and/or mask" , node .Name )
119- }
120- ipNets = append (ipNets , & net.IPNet {IP : ip , Mask : mask })
12180 }
122- return ipNets , nil
123- }
124-
125- func isIPWithinAllSubnets (ipNets []* net.IPNet , ip net.IP ) bool {
126- if len (ipNets ) == 0 {
127- return false
128- }
129- for _ , ipNet := range ipNets {
130- if ! ipNet .Contains (ip ) {
131- return false
132- }
133- }
134- return true
81+ return ipa , nil
13582}
13683
13784func (pia * primaryIPAllocator ) IncrementAndGetNextV4 (times int ) (net.IP , error ) {
@@ -148,12 +95,9 @@ func (pia *primaryIPAllocator) AllocateNextV4() (net.IP, error) {
14895 if pia .v4 == nil {
14996 return nil , fmt .Errorf ("IPv4 is not enable " )
15097 }
151- if pia .v4 .net == nil {
152- return nil , fmt .Errorf ("IPv4 is not enabled but Allocation request was called" )
153- }
15498 pia .mu .Lock ()
15599 defer pia .mu .Unlock ()
156- return allocateIP ( pia .nodeClient , pia . v4 .AllocateNextIP )
100+ return pia .v4 .AllocateNext ( )
157101}
158102
159103func (pia * primaryIPAllocator ) IncrementAndGetNextV6 (times int ) (net.IP , error ) {
@@ -170,51 +114,7 @@ func (pia primaryIPAllocator) AllocateNextV6() (net.IP, error) {
170114 if pia .v6 == nil {
171115 return nil , fmt .Errorf ("IPv6 is not enabled but Allocation request was called" )
172116 }
173- if pia .v6 .net == nil {
174- return nil , fmt .Errorf ("ipv6 network is not set" )
175- }
176117 pia .mu .Lock ()
177118 defer pia .mu .Unlock ()
178- return allocateIP (pia .nodeClient , pia .v6 .AllocateNextIP )
179- }
180-
181- type allocNextFn func () (net.IP , error )
182-
183- func allocateIP (nodeClient v1.NodeInterface , allocateFn allocNextFn ) (net.IP , error ) {
184- nodeList , err := nodeClient .List (context .TODO (), metav1.ListOptions {})
185- if err != nil {
186- return nil , fmt .Errorf ("failed to list nodes: %v" , err )
187- }
188- for {
189- nextIP , err := allocateFn ()
190- if err != nil {
191- return nil , fmt .Errorf ("failed to allocated next IP address: %v" , err )
192- }
193- firstOctet := nextIP [len (nextIP )- 1 ]
194- // skip 0 and 1
195- if firstOctet == 0 || firstOctet == 1 {
196- continue
197- }
198- isConflict , err := isConflictWithExistingHostIPs (nodeList .Items , nextIP )
199- if err != nil {
200- return nil , fmt .Errorf ("failed to determine if IP conflicts with existing IPs: %v" , err )
201- }
202- if ! isConflict {
203- return nextIP , nil
204- }
205- }
206- }
207-
208- func isConflictWithExistingHostIPs (nodes []corev1.Node , ip net.IP ) (bool , error ) {
209- ipStr := ip .String ()
210- for _ , node := range nodes {
211- nodeIPsSet , err := util .ParseNodeHostCIDRsDropNetMask (& node )
212- if err != nil {
213- return false , fmt .Errorf ("failed to parse node %s primary annotation info: %v" , node .Name , err )
214- }
215- if nodeIPsSet .Has (ipStr ) {
216- return true , nil
217- }
218- }
219- return false , nil
119+ return pia .v6 .AllocateNext ()
220120}
0 commit comments