@@ -18,6 +18,7 @@ import (
18
18
"github.com/cloudnativelabs/kube-router/v2/pkg/metrics"
19
19
"github.com/cloudnativelabs/kube-router/v2/pkg/options"
20
20
"github.com/cloudnativelabs/kube-router/v2/pkg/routes"
21
+ "github.com/cloudnativelabs/kube-router/v2/pkg/tunnels"
21
22
"github.com/cloudnativelabs/kube-router/v2/pkg/utils"
22
23
"github.com/coreos/go-iptables/iptables"
23
24
gobgpapi "github.com/osrg/gobgp/v3/api"
@@ -67,15 +68,6 @@ const (
67
68
bgpCommunityMaxPartSize = 16
68
69
routeReflectorMaxID = 32
69
70
ipv4MaskMinBits = 32
70
-
71
- encapTypeFOU = "fou"
72
- encapTypeIPIP = "ipip"
73
-
74
- ipipModev4 = "ipip"
75
- ipipModev6 = "ip6ip6"
76
-
77
- maxPort = uint16 (65535 )
78
- minPort = uint16 (1024 )
79
71
)
80
72
81
73
// NetworkRoutingController is struct to hold necessary information required by controller
@@ -111,8 +103,6 @@ type NetworkRoutingController struct {
111
103
iptablesCmdHandlers map [v1core.IPFamily ]utils.IPTablesHandler
112
104
enableOverlays bool
113
105
overlayType string
114
- overlayEncap string
115
- overlayEncapPort uint16
116
106
peerMultihopTTL uint8
117
107
MetricsEnabled bool
118
108
bgpServerStarted bool
@@ -137,6 +127,7 @@ type NetworkRoutingController struct {
137
127
ipsetMutex * sync.Mutex
138
128
routeSyncer routes.RouteSyncer
139
129
pbr routes.PBRer
130
+ tunneler tunnels.Tunneler
140
131
141
132
nodeLister cache.Indexer
142
133
svcLister cache.Indexer
@@ -185,7 +176,7 @@ func (nrc *NetworkRoutingController) Run(healthChan chan<- *healthcheck.Controll
185
176
if err != nil {
186
177
klog .Errorf ("Failed to enable required policy based routing: %s" , err .Error ())
187
178
}
188
- if nrc .overlayEncap == "fou" {
179
+ if nrc .tunneler . EncapType () == tunnels . EncapTypeFOU {
189
180
// enable FoU module for the overlay tunnel
190
181
if _ , err := exec .Command ("modprobe" , "fou" ).CombinedOutput (); err != nil {
191
182
klog .Errorf ("Failed to enable FoU for tunnel overlay: %s" , err .Error ())
@@ -581,7 +572,7 @@ func (nrc *NetworkRoutingController) injectRoute(path *gobgpapi.Path) error {
581
572
return err
582
573
}
583
574
584
- tunnelName := generateTunnelName (nextHop .String ())
575
+ tunnelName := tunnels . GenerateTunnelName (nextHop .String ())
585
576
checkNHSameSubnet := func (needle net.IP , haystack []net.IP ) bool {
586
577
for _ , nodeIP := range haystack {
587
578
nodeSubnet , _ , err := utils .GetNodeSubnet (nodeIP , nil )
@@ -622,7 +613,7 @@ func (nrc *NetworkRoutingController) injectRoute(path *gobgpapi.Path) error {
622
613
nextHop .String ())
623
614
// Also delete route from state map so that it doesn't get re-synced after deletion
624
615
nrc .routeSyncer .DelInjectedRoute (dst )
625
- nrc . cleanupTunnel (dst , tunnelName )
616
+ tunnels . CleanupTunnel (dst , tunnelName )
626
617
return nil
627
618
}
628
619
@@ -648,14 +639,14 @@ func (nrc *NetworkRoutingController) injectRoute(path *gobgpapi.Path) error {
648
639
// if the user has disabled overlays, don't create tunnels. If we're not creating a tunnel, check to see if there is
649
640
// any cleanup that needs to happen.
650
641
if shouldCreateTunnel () {
651
- link , err = nrc .setupOverlayTunnel (tunnelName , nextHop , dst )
642
+ link , err = nrc .tunneler . SetupOverlayTunnel (tunnelName , nextHop , dst )
652
643
if err != nil {
653
644
return err
654
645
}
655
646
} else {
656
647
// knowing that a tunnel shouldn't exist for this route, check to see if there are any lingering tunnels /
657
648
// routes that need to be cleaned up.
658
- nrc . cleanupTunnel (dst , tunnelName )
649
+ tunnels . CleanupTunnel (dst , tunnelName )
659
650
}
660
651
661
652
switch {
@@ -724,164 +715,6 @@ func (nrc *NetworkRoutingController) isPeerEstablished(peerIP string) (bool, err
724
715
return peerConnected , nil
725
716
}
726
717
727
- // cleanupTunnel removes any traces of tunnels / routes that were setup by nrc.setupOverlayTunnel() and are no longer
728
- // needed. All errors are logged only, as we want to attempt to perform all cleanup actions regardless of their success
729
- func (nrc * NetworkRoutingController ) cleanupTunnel (destinationSubnet * net.IPNet , tunnelName string ) {
730
- klog .V (1 ).Infof ("Cleaning up old routes for %s if there are any" , destinationSubnet .String ())
731
- if err := routes .DeleteByDestination (destinationSubnet ); err != nil {
732
- klog .Errorf ("Failed to cleanup routes: %v" , err )
733
- }
734
-
735
- klog .V (1 ).Infof ("Cleaning up any lingering tunnel interfaces named: %s" , tunnelName )
736
- if link , err := netlink .LinkByName (tunnelName ); err == nil {
737
- if err = netlink .LinkDel (link ); err != nil {
738
- klog .Errorf ("Failed to delete tunnel link for the node due to " + err .Error ())
739
- }
740
- }
741
- }
742
-
743
- // setupOverlayTunnel attempts to create a tunnel link and corresponding routes for IPIP based overlay networks
744
- func (nrc * NetworkRoutingController ) setupOverlayTunnel (tunnelName string , nextHop net.IP ,
745
- nextHopSubnet * net.IPNet ) (netlink.Link , error ) {
746
- var out []byte
747
- link , err := netlink .LinkByName (tunnelName )
748
-
749
- var bestIPForFamily net.IP
750
- var ipipMode , fouLinkType string
751
- isIPv6 := false
752
- ipBase := make ([]string , 0 )
753
- strFormattedEncapPort := strconv .FormatInt (int64 (nrc .overlayEncapPort ), 10 )
754
-
755
- if nextHop .To4 () != nil {
756
- bestIPForFamily = nrc .krNode .FindBestIPv4NodeAddress ()
757
- ipipMode = encapTypeIPIP
758
- fouLinkType = ipipModev4
759
- } else {
760
- // Need to activate the ip command in IPv6 mode
761
- ipBase = append (ipBase , "-6" )
762
- bestIPForFamily = nrc .krNode .FindBestIPv6NodeAddress ()
763
- ipipMode = ipipModev6
764
- fouLinkType = "ip6tnl"
765
- isIPv6 = true
766
- }
767
- if nil == bestIPForFamily {
768
- return nil , fmt .Errorf ("not able to find an appropriate configured IP address on node for destination " +
769
- "IP family: %s" , nextHop .String ())
770
- }
771
-
772
- // This indicated that the tunnel already exists, so it's possible that there might be nothing more needed. However,
773
- // it is also possible that the user changed the encap type, so we need to make sure that the encap type matches
774
- // and if it doesn't, create it
775
- recreate := false
776
- if err == nil {
777
- klog .V (1 ).Infof ("Tunnel interface: %s with encap type %s for the node %s already exists." ,
778
- tunnelName , link .Attrs ().EncapType , nextHop .String ())
779
-
780
- switch nrc .overlayEncap {
781
- case encapTypeIPIP :
782
- if linkFOUEnabled (tunnelName ) {
783
- klog .Infof ("Was configured to use ipip tunnels, but found existing fou tunnels in place, cleaning up" )
784
- recreate = true
785
-
786
- // Even though we are setup for IPIP tunels we have existing tunnels that are FoU tunnels, remove them
787
- // so that we can recreate them as IPIP
788
- nrc .cleanupTunnel (nextHopSubnet , tunnelName )
789
-
790
- // If we are transitioning from FoU to IPIP we also need to clean up the old FoU port if it exists
791
- if fouPortAndProtoExist (nrc .overlayEncapPort , isIPv6 ) {
792
- fouArgs := ipBase
793
- fouArgs = append (fouArgs , "fou" , "del" , "port" , strFormattedEncapPort )
794
- out , err := exec .Command ("ip" , fouArgs ... ).CombinedOutput ()
795
- if err != nil {
796
- klog .Warningf ("failed to clean up previous FoU tunnel port (this is only a warning because it " +
797
- "won't stop kube-router from working for now, but still shouldn't have happened) - error: " +
798
- "%v, output %s" , err , out )
799
- }
800
- }
801
- }
802
- case encapTypeFOU :
803
- if ! linkFOUEnabled (tunnelName ) {
804
- klog .Infof ("Was configured to use fou tunnels, but found existing ipip tunnels in place, cleaning up" )
805
- recreate = true
806
- // Even though we are setup for FoU tunels we have existing tunnels that are IPIP tunnels, remove them
807
- // so that we can recreate them as IPIP
808
- nrc .cleanupTunnel (nextHopSubnet , tunnelName )
809
- }
810
- }
811
- }
812
-
813
- // an error here indicates that the tunnel didn't exist, so we need to create it, if it already exists there's
814
- // nothing to do here
815
- if err != nil || recreate {
816
- klog .Infof ("Creating tunnel %s of type %s with encap %s for destination %s" ,
817
- tunnelName , fouLinkType , nrc .overlayEncap , nextHop .String ())
818
- cmdArgs := ipBase
819
- switch nrc .overlayEncap {
820
- case encapTypeIPIP :
821
- // Plain IPIP tunnel without any encapsulation
822
- cmdArgs = append (cmdArgs , "tunnel" , "add" , tunnelName , "mode" , ipipMode , "local" , bestIPForFamily .String (),
823
- "remote" , nextHop .String ())
824
-
825
- case encapTypeFOU :
826
- // Ensure that the FOU tunnel port is set correctly
827
- if ! fouPortAndProtoExist (nrc .overlayEncapPort , isIPv6 ) {
828
- fouArgs := ipBase
829
- fouArgs = append (fouArgs , "fou" , "add" , "port" , strFormattedEncapPort , "gue" )
830
- out , err := exec .Command ("ip" , fouArgs ... ).CombinedOutput ()
831
- if err != nil {
832
- //nolint:goconst // don't need to make error messages a constant
833
- return nil , fmt .Errorf ("route not injected for the route advertised by the node %s " +
834
- "Failed to set FoU tunnel port - error: %s, output: %s" , tunnelName , err , string (out ))
835
- }
836
- }
837
-
838
- // Prep IPIP tunnel for FOU encapsulation
839
- cmdArgs = append (cmdArgs , "link" , "add" , "name" , tunnelName , "type" , fouLinkType , "remote" , nextHop .String (),
840
- "local" , bestIPForFamily .String (), "ttl" , "225" , "encap" , "gue" , "encap-sport" , "auto" , "encap-dport" ,
841
- strFormattedEncapPort , "mode" , ipipMode )
842
-
843
- default :
844
- return nil , fmt .Errorf ("unknown tunnel encapsulation was passed: %s, unable to continue with overlay " +
845
- "setup" , nrc .overlayEncap )
846
- }
847
-
848
- klog .V (2 ).Infof ("Executing the following command to create tunnel: ip %s" , cmdArgs )
849
- out , err := exec .Command ("ip" , cmdArgs ... ).CombinedOutput ()
850
- if err != nil {
851
- return nil , fmt .Errorf ("route not injected for the route advertised by the node %s " +
852
- "Failed to create tunnel interface %s. error: %s, output: %s" ,
853
- nextHop , tunnelName , err , string (out ))
854
- }
855
-
856
- link , err = netlink .LinkByName (tunnelName )
857
- if err != nil {
858
- return nil , fmt .Errorf ("route not injected for the route advertised by the node %s " +
859
- "Failed to get tunnel interface by name error: %s" , tunnelName , err )
860
- }
861
- if err = netlink .LinkSetUp (link ); err != nil {
862
- return nil , errors .New ("Failed to bring tunnel interface " + tunnelName + " up due to: " + err .Error ())
863
- }
864
- }
865
-
866
- // Now that the tunnel link exists, we need to add a route to it, so the node knows where to send traffic bound for
867
- // this interface
868
- //nolint:gocritic // we understand that we are appending to a new slice
869
- cmdArgs := append (ipBase , "route" , "list" , "table" , routes .CustomTableID )
870
- out , err = exec .Command ("ip" , cmdArgs ... ).CombinedOutput ()
871
- // This used to be "dev "+tunnelName+" scope" but this isn't consistent with IPv6's output, so we changed it to just
872
- // "dev "+tunnelName, but at this point I'm unsure if there was a good reason for adding scope on before, so that's
873
- // why this comment is here.
874
- if err != nil || ! strings .Contains (string (out ), "dev " + tunnelName ) {
875
- //nolint:gocritic // we understand that we are appending to a new slice
876
- cmdArgs = append (ipBase , "route" , "add" , nextHop .String (), "dev" , tunnelName , "table" , routes .CustomTableID )
877
- if out , err = exec .Command ("ip" , cmdArgs ... ).CombinedOutput (); err != nil {
878
- return nil , fmt .Errorf ("failed to add route in custom route table, err: %s, output: %s" , err , string (out ))
879
- }
880
- }
881
-
882
- return link , nil
883
- }
884
-
885
718
// Cleanup performs the cleanup of configurations done
886
719
func (nrc * NetworkRoutingController ) Cleanup () {
887
720
klog .Infof ("Cleaning up NetworkRoutesController configurations" )
@@ -1533,18 +1366,16 @@ func NewNetworkRoutingController(clientset kubernetes.Interface,
1533
1366
nrc .autoMTU = kubeRouterConfig .AutoMTU
1534
1367
nrc .enableOverlays = kubeRouterConfig .EnableOverlay
1535
1368
nrc .overlayType = kubeRouterConfig .OverlayType
1536
- nrc .overlayEncap = kubeRouterConfig .OverlayEncap
1537
- switch nrc .overlayEncap {
1538
- case encapTypeIPIP :
1539
- case encapTypeFOU :
1540
- default :
1541
- return nil , fmt .Errorf ("unknown --overlay-encap option '%s' selected, unable to continue" , nrc .overlayEncap )
1369
+ overlayEncap , err := tunnels .ParseEncapType (kubeRouterConfig .OverlayEncap )
1370
+ if err != nil {
1371
+ return nil , fmt .Errorf ("unknown --overlay-encap option '%s' selected, unable to continue" , overlayEncap )
1542
1372
}
1543
- nrc . overlayEncapPort = kubeRouterConfig .OverlayEncapPort
1544
- if nrc . overlayEncapPort > maxPort || nrc . overlayEncapPort < minPort {
1545
- return nil , fmt .Errorf ("specified encap port is out of range of valid ports: %d, valid range is from %d to %d " ,
1546
- nrc . overlayEncapPort , minPort , maxPort )
1373
+ overlayEncapPort , err := tunnels . ParseEncapPort ( kubeRouterConfig .OverlayEncapPort )
1374
+ if err != nil {
1375
+ return nil , fmt .Errorf ("unknown --overlay- encap- port option '%d' selected, unable to continue, err: %v " ,
1376
+ overlayEncapPort , err )
1547
1377
}
1378
+ nrc .tunneler = tunnels .NewOverlayTunnel (nrc .krNode , overlayEncap , overlayEncapPort )
1548
1379
nrc .CNIFirewallSetup = sync .NewCond (& sync.Mutex {})
1549
1380
1550
1381
nrc .bgpPort = kubeRouterConfig .BGPPort
0 commit comments