@@ -18,11 +18,14 @@ import (
18
18
"context"
19
19
"fmt"
20
20
"net"
21
+ "net/netip"
22
+ "sync"
21
23
"time"
22
24
23
25
"github.com/containernetworking/plugins/pkg/ip"
24
26
corev1 "k8s.io/api/core/v1"
25
27
"k8s.io/apimachinery/pkg/labels"
28
+ "k8s.io/apimachinery/pkg/util/sets"
26
29
"k8s.io/apimachinery/pkg/util/wait"
27
30
coreinformers "k8s.io/client-go/informers/core/v1"
28
31
corelisters "k8s.io/client-go/listers/core/v1"
@@ -77,7 +80,13 @@ type Controller struct {
77
80
// installedNodes records routes and flows installation states of Nodes.
78
81
// The key is the host name of the Node, the value is the nodeRouteInfo of the Node.
79
82
// A node will be in the map after its flows and routes are installed successfully.
80
- installedNodes cache.Indexer
83
+ installedNodes cache.Indexer
84
+ // podSubnetsMutex protects access to the podSubnets set.
85
+ podSubnetsMutex sync.RWMutex
86
+ // podSubnets is a set which stores all known PodCIDRs in the cluster as masked netip.Prefix objects.
87
+ podSubnets sets.Set [netip.Prefix ]
88
+ maskSizeV4 int
89
+ maskSizeV6 int
81
90
wireGuardClient wireguard.Interface
82
91
// ipsecCertificateManager is useful for determining whether the ipsec certificate has been configured
83
92
// or not when IPsec is enabled with "cert" mode. The NodeRouteController must wait for the certificate
@@ -124,10 +133,21 @@ func NewNodeRouteController(
124
133
},
125
134
),
126
135
installedNodes : cache .NewIndexer (nodeRouteInfoKeyFunc , cache.Indexers {nodeRouteInfoPodCIDRIndexName : nodeRouteInfoPodCIDRIndexFunc }),
136
+ podSubnets : sets .New [netip.Prefix ](),
127
137
wireGuardClient : wireguardClient ,
128
138
ipsecCertificateManager : ipsecCertificateManager ,
129
139
flowRestoreCompleteWait : flowRestoreCompleteWait .Increment (),
130
140
}
141
+ if nodeConfig .PodIPv4CIDR != nil {
142
+ prefix , _ := cidrToPrefix (nodeConfig .PodIPv4CIDR )
143
+ controller .podSubnets .Insert (prefix )
144
+ controller .maskSizeV4 = prefix .Bits ()
145
+ }
146
+ if nodeConfig .PodIPv6CIDR != nil {
147
+ prefix , _ := cidrToPrefix (nodeConfig .PodIPv6CIDR )
148
+ controller .podSubnets .Insert (prefix )
149
+ controller .maskSizeV6 = prefix .Bits ()
150
+ }
131
151
registration , _ := nodeInformer .Informer ().AddEventHandlerWithResyncPeriod (
132
152
cache.ResourceEventHandlerDetailedFuncs {
133
153
AddFunc : func (cur interface {}, isInInitialList bool ) {
@@ -379,7 +399,7 @@ func (c *Controller) Run(stopCh <-chan struct{}) {
379
399
go func () {
380
400
// When the initial list of Nodes has been processed, we decrement flowRestoreCompleteWait.
381
401
err := wait .PollUntilContextCancel (wait .ContextForChannel (stopCh ), 100 * time .Millisecond , true , func (ctx context.Context ) (done bool , err error ) {
382
- return c .hasProcessedInitialList . HasSynced (), nil
402
+ return c .HasSynced (), nil
383
403
})
384
404
// An error here means the context has been cancelled, which means that the stopCh
385
405
// has been closed. While it is still possible for c.hasProcessedInitialList.HasSynced
@@ -395,6 +415,11 @@ func (c *Controller) Run(stopCh <-chan struct{}) {
395
415
<- stopCh
396
416
}
397
417
418
+ // HasSynced returns true when the initial list of Nodes has been processed by the controller.
419
+ func (c * Controller ) HasSynced () bool {
420
+ return c .hasProcessedInitialList .HasSynced ()
421
+ }
422
+
398
423
// worker is a long-running function that will continually call the processNextWorkItem function in
399
424
// order to read and process a message on the workqueue.
400
425
func (c * Controller ) worker () {
@@ -482,6 +507,12 @@ func (c *Controller) deleteNodeRoute(nodeName string) error {
482
507
return fmt .Errorf ("failed to uninstall flows to Node %s: %v" , nodeName , err )
483
508
}
484
509
c .installedNodes .Delete (obj )
510
+ func () {
511
+ subnets , _ := cidrsToPrefixes (nodeRouteInfo .podCIDRs )
512
+ c .podSubnetsMutex .Lock ()
513
+ defer c .podSubnetsMutex .Unlock ()
514
+ c .podSubnets .Delete (subnets ... )
515
+ }()
485
516
486
517
if c .networkConfig .TrafficEncryptionMode == config .TrafficEncryptionModeIPSec {
487
518
interfaceConfig , ok := c .interfaceStore .GetNodeTunnelInterface (nodeName )
@@ -575,6 +606,13 @@ func (c *Controller) addNodeRoute(nodeName string, node *corev1.Node) error {
575
606
peerNodeIP = peerNodeIPs .IPv6
576
607
}
577
608
609
+ func () {
610
+ subnet , _ := cidrToPrefix (peerPodCIDR )
611
+ c .podSubnetsMutex .Lock ()
612
+ defer c .podSubnetsMutex .Unlock ()
613
+ c .podSubnets .Insert (subnet )
614
+ }()
615
+
578
616
klog .InfoS ("Adding route and flow to Node" , "Node" , nodeName , "podCIDR" , podCIDR ,
579
617
"peerNodeIP" , peerNodeIP )
580
618
}
@@ -773,40 +811,31 @@ func ParseTunnelInterfaceConfig(
773
811
return interfaceConfig
774
812
}
775
813
776
- func (c * Controller ) IPInPodSubnets (ip net.IP ) bool {
777
- var ipCIDR * net.IPNet
778
- var curNodeCIDRStr string
779
- if ip .To4 () != nil {
780
- var podIPv4CIDRMaskSize int
781
- if c .nodeConfig .PodIPv4CIDR != nil {
782
- curNodeCIDRStr = c .nodeConfig .PodIPv4CIDR .String ()
783
- podIPv4CIDRMaskSize , _ = c .nodeConfig .PodIPv4CIDR .Mask .Size ()
784
- } else {
785
- return false
786
- }
787
- v4Mask := net .CIDRMask (podIPv4CIDRMaskSize , utilip .V4BitLen )
788
- ipCIDR = & net.IPNet {
789
- IP : ip .Mask (v4Mask ),
790
- Mask : v4Mask ,
791
- }
792
-
814
+ func (c * Controller ) findPodSubnetForIP (ip netip.Addr ) (netip.Prefix , bool ) {
815
+ var maskSize int
816
+ if ip .Is4 () {
817
+ maskSize = c .maskSizeV4
793
818
} else {
794
- var podIPv6CIDRMaskSize int
795
- if c .nodeConfig .PodIPv6CIDR != nil {
796
- curNodeCIDRStr = c .nodeConfig .PodIPv6CIDR .String ()
797
- podIPv6CIDRMaskSize , _ = c .nodeConfig .PodIPv6CIDR .Mask .Size ()
798
- } else {
799
- return false
800
- }
801
- v6Mask := net .CIDRMask (podIPv6CIDRMaskSize , utilip .V6BitLen )
802
- ipCIDR = & net.IPNet {
803
- IP : ip .Mask (v6Mask ),
804
- Mask : v6Mask ,
805
- }
819
+ maskSize = c .maskSizeV6
806
820
}
807
- ipCIDRStr := ipCIDR .String ()
808
- nodeInCluster , _ := c .installedNodes .ByIndex (nodeRouteInfoPodCIDRIndexName , ipCIDRStr )
809
- return len (nodeInCluster ) > 0 || ipCIDRStr == curNodeCIDRStr
821
+ if maskSize == 0 {
822
+ return netip.Prefix {}, false
823
+ }
824
+ prefix , _ := ip .Prefix (maskSize )
825
+ c .podSubnetsMutex .RLock ()
826
+ defer c .podSubnetsMutex .RUnlock ()
827
+ return prefix , c .podSubnets .Has (prefix )
828
+ }
829
+
830
+ // LookupIPInPodSubnets returns two boolean values. The first one indicates whether the IP can be
831
+ // found in a PodCIDR for one of the cluster Nodes. The second one indicates whether the IP is used
832
+ // as a gateway IP. The second boolean value can only be true if the first one is true.
833
+ func (c * Controller ) LookupIPInPodSubnets (ip netip.Addr ) (bool , bool ) {
834
+ prefix , ok := c .findPodSubnetForIP (ip )
835
+ if ! ok {
836
+ return false , false
837
+ }
838
+ return ok , ip == util .GetGatewayIPForPodPrefix (prefix )
810
839
}
811
840
812
841
// getNodeMAC gets Node's br-int MAC from its annotation. It is only for Windows Noencap mode.
@@ -821,3 +850,24 @@ func getNodeMAC(node *corev1.Node) (net.HardwareAddr, error) {
821
850
}
822
851
return mac , nil
823
852
}
853
+
854
+ func cidrToPrefix (cidr * net.IPNet ) (netip.Prefix , error ) {
855
+ addr , ok := netip .AddrFromSlice (cidr .IP )
856
+ if ! ok {
857
+ return netip.Prefix {}, fmt .Errorf ("invalid IP in CIDR: %v" , cidr )
858
+ }
859
+ size , _ := cidr .Mask .Size ()
860
+ return addr .Prefix (size )
861
+ }
862
+
863
+ func cidrsToPrefixes (cidrs []* net.IPNet ) ([]netip.Prefix , error ) {
864
+ prefixes := make ([]netip.Prefix , len (cidrs ))
865
+ for idx := range cidrs {
866
+ prefix , err := cidrToPrefix (cidrs [idx ])
867
+ if err != nil {
868
+ return nil , err
869
+ }
870
+ prefixes [idx ] = prefix
871
+ }
872
+ return prefixes , nil
873
+ }
0 commit comments