@@ -490,10 +490,7 @@ func (eit *EgressIPTracker) findEgressIPAllocation(ip net.IP, allocation map[str
490
490
if node .offline {
491
491
continue
492
492
}
493
- egressIPs , exists := allocation [node .nodeName ]
494
- if ! exists {
495
- continue
496
- }
493
+ egressIPs := allocation [node .nodeName ]
497
494
for _ , parsed := range node .parsedCIDRs {
498
495
if parsed .Contains (ip ) {
499
496
if bestNode != "" {
@@ -511,13 +508,13 @@ func (eit *EgressIPTracker) findEgressIPAllocation(ip net.IP, allocation map[str
511
508
return bestNode , otherNodes
512
509
}
513
510
514
- // ReallocateEgressIPs returns a map from Node name to array-of-Egress-IP for all auto-allocated egress IPs
515
- func (eit * EgressIPTracker ) ReallocateEgressIPs () map [string ][]string {
516
- eit .Lock ()
517
- defer eit .Unlock ()
511
+ func (eit * EgressIPTracker ) makeEmptyAllocation () (map [string ][]string , map [string ]bool ) {
512
+ return make (map [string ][]string ), make (map [string ]bool )
513
+ }
514
+
515
+ func (eit * EgressIPTracker ) allocateExistingEgressIPs (allocation map [string ][]string , alreadyAllocated map [string ]bool ) bool {
516
+ removedEgressIPs := false
518
517
519
- allocation := make (map [string ][]string )
520
- alreadyAllocated := make (map [string ]bool )
521
518
for _ , node := range eit .nodes {
522
519
if len (node .parsedCIDRs ) > 0 {
523
520
allocation [node .nodeName ] = make ([]string , 0 , node .requestedIPs .Len ())
@@ -526,7 +523,7 @@ func (eit *EgressIPTracker) ReallocateEgressIPs() map[string][]string {
526
523
// For each active egress IP, if it still fits within some egress CIDR on its node,
527
524
// add it to that node's allocation.
528
525
for egressIP , eip := range eit .egressIPs {
529
- if eip .assignedNodeIP == "" {
526
+ if eip .assignedNodeIP == "" || alreadyAllocated [ egressIP ] {
530
527
continue
531
528
}
532
529
node := eip .nodes [0 ]
@@ -539,13 +536,19 @@ func (eit *EgressIPTracker) ReallocateEgressIPs() map[string][]string {
539
536
}
540
537
if found && ! node .offline {
541
538
allocation [node .nodeName ] = append (allocation [node .nodeName ], egressIP )
539
+ } else {
540
+ removedEgressIPs = true
542
541
}
543
542
// (We set alreadyAllocated even if the egressIP will be removed from
544
543
// its current node; we can't assign it to a new node until the next
545
544
// reallocation.)
546
545
alreadyAllocated [egressIP ] = true
547
546
}
548
547
548
+ return removedEgressIPs
549
+ }
550
+
551
+ func (eit * EgressIPTracker ) allocateNewEgressIPs (allocation map [string ][]string , alreadyAllocated map [string ]bool ) {
549
552
// Allocate pending egress IPs that can only go to a single node
550
553
for egressIP , eip := range eit .egressIPs {
551
554
if alreadyAllocated [egressIP ] {
@@ -567,6 +570,52 @@ func (eit *EgressIPTracker) ReallocateEgressIPs() map[string][]string {
567
570
allocation [nodeName ] = append (allocation [nodeName ], egressIP )
568
571
}
569
572
}
573
+ }
574
+
575
+ // ReallocateEgressIPs returns a map from Node name to array-of-Egress-IP for all auto-allocated egress IPs
576
+ func (eit * EgressIPTracker ) ReallocateEgressIPs () map [string ][]string {
577
+ eit .Lock ()
578
+ defer eit .Unlock ()
579
+
580
+ allocation , alreadyAllocated := eit .makeEmptyAllocation ()
581
+ removedEgressIPs := eit .allocateExistingEgressIPs (allocation , alreadyAllocated )
582
+ eit .allocateNewEgressIPs (allocation , alreadyAllocated )
583
+ if removedEgressIPs {
584
+ // Process the removals now; we'll get called again afterward and can
585
+ // check for balance then.
586
+ return allocation
587
+ }
588
+
589
+ // Compare the allocation to what we would have gotten if we started from scratch,
590
+ // to see if things have gotten too unbalanced. (In particular, if a node goes
591
+ // offline, gets emptied, and then comes back online, we want to move a bunch of
592
+ // egress IPs back onto that node.)
593
+ fullReallocation , alreadyAllocated := eit .makeEmptyAllocation ()
594
+ eit .allocateNewEgressIPs (fullReallocation , alreadyAllocated )
595
+
596
+ emptyNodes := []string {}
597
+ for nodeName , fullEgressIPs := range fullReallocation {
598
+ incrementalEgressIPs := allocation [nodeName ]
599
+ if len (incrementalEgressIPs ) < len (fullEgressIPs )/ 2 {
600
+ emptyNodes = append (emptyNodes , nodeName )
601
+ }
602
+ }
603
+
604
+ if len (emptyNodes ) > 0 {
605
+ // Make a new incremental allocation, but skipping all of the egress IPs
606
+ // that got assigned to the "empty" nodes in the full reallocation; this
607
+ // will cause them to be dropped from their current nodes and then later
608
+ // reassigned (to one of the "empty" nodes, for balance).
609
+ allocation , alreadyAllocated = eit .makeEmptyAllocation ()
610
+ for _ , nodeName := range emptyNodes {
611
+ for _ , egressIP := range fullReallocation [nodeName ] {
612
+ alreadyAllocated [egressIP ] = true
613
+ }
614
+ }
615
+ eit .allocateExistingEgressIPs (allocation , alreadyAllocated )
616
+ eit .allocateNewEgressIPs (allocation , alreadyAllocated )
617
+ eit .updateEgressCIDRs = true
618
+ }
570
619
571
620
return allocation
572
621
}
0 commit comments