Skip to content

Commit

Permalink
Enabled traffic toward ExternalCIDR
Browse files Browse the repository at this point in the history
This PR enables peered clusters to exchange traffic toward ExternalCIDR, as they already do with PodCIDR. To solve this problem, routing drives supported by Liqo have been modified in such a way that now routing tables hold not only PodCIDR destinations but also ExternalCIDR destinations.
  • Loading branch information
davidefalcone1 committed Jun 24, 2021
1 parent 5b7d99a commit 1b30550
Show file tree
Hide file tree
Showing 11 changed files with 290 additions and 100 deletions.
2 changes: 1 addition & 1 deletion pkg/liqonet/iptables/iptables.go
Expand Up @@ -704,7 +704,7 @@ func getChainRulesPerCluster(tep *netv1alpha1.TunnelEndpoint) (map[string][]IPTa
}
clusterID := tep.Spec.ClusterID
localRemappedPodCIDR, remotePodCIDR := utils.GetPodCIDRS(tep)
localRemappedExternalCIDR := utils.GetExternalCIDR(tep)
localRemappedExternalCIDR, _ := utils.GetExternalCIDRS(tep)

// Init chain rules
chainRules := make(map[string][]IPTableRule)
Expand Down
9 changes: 5 additions & 4 deletions pkg/liqonet/routing/common.go
Expand Up @@ -210,22 +210,23 @@ func flushRulesForRoutingTable(routingTableID int) error {
return nil
}

func getRouteConfig(tep *v1alpha1.TunnelEndpoint, podIP string) (dstNet, gatewayIP string, iFaceIndex int, err error) {
_, dstNet = utils.GetPodCIDRS(tep)
func getRouteConfig(tep *v1alpha1.TunnelEndpoint, podIP string) (dstPodCIDRNet, dstExternalCIDRNet, gatewayIP string, iFaceIndex int, err error) {
_, dstPodCIDRNet = utils.GetPodCIDRS(tep)
_, dstExternalCIDRNet = utils.GetExternalCIDRS(tep)
// Check if we are running on the same host as the gateway pod.
if tep.Status.GatewayIP != podIP {
// If the pod is not running on the same host then set the IP address of the Gateway as next hop.
gatewayIP = tep.Status.GatewayIP
// Get the iFace index for the IP address of the Gateway pod.
iFaceIndex, err = getIFaceIndexForIP(gatewayIP)
if err != nil {
return dstNet, gatewayIP, iFaceIndex, err
return dstPodCIDRNet, dstExternalCIDRNet, gatewayIP, iFaceIndex, err
}
} else {
// Running on the same host as the Gateway then set the index of the veth device living on the same network namespace.
iFaceIndex = tep.Status.VethIFaceIndex
}
return dstNet, gatewayIP, iFaceIndex, err
return dstPodCIDRNet, dstExternalCIDRNet, gatewayIP, iFaceIndex, err
}

func getIFaceIndexForIP(ipAddress string) (int, error) {
Expand Down
12 changes: 7 additions & 5 deletions pkg/liqonet/routing/common_test.go
Expand Up @@ -470,19 +470,21 @@ var _ = Describe("Common", func() {

Context("when the the operator has same IP address as the Gateway pod", func() {
It("should return no error", func() {
dstNet, gwIP, iFaceIndex, err := getRouteConfig(&tep, ipAddress2NoSubnet)
dstPodCIDRNet, dstExternalCIDRNet, gwIP, iFaceIndex, err := getRouteConfig(&tep, ipAddress2NoSubnet)
Expect(err).NotTo(HaveOccurred())
Expect(dstNet).Should(Equal(tep.Status.RemoteNATPodCIDR))
Expect(dstPodCIDRNet).Should(Equal(tep.Status.RemoteNATPodCIDR))
Expect(dstExternalCIDRNet).Should(Equal(tep.Status.RemoteNATExternalCIDR))
Expect(gwIP).Should(Equal(""))
Expect(iFaceIndex).Should(BeNumerically("==", tep.Status.VethIFaceIndex))
})
})

Context("when the the operator is not running on same node as the Gateway pod", func() {
It("should return nil and a link index of the interface through which the Gateway is reachable", func() {
dstNet, gwIP, iFaceIndex, err := getRouteConfig(&tep, notReachableIP)
dstPodCIDRNet, dstExternalCIDRNet, gwIP, iFaceIndex, err := getRouteConfig(&tep, notReachableIP)
Expect(err).NotTo(HaveOccurred())
Expect(dstNet).Should(Equal(tep.Status.RemoteNATPodCIDR))
Expect(dstPodCIDRNet).Should(Equal(tep.Status.RemoteNATPodCIDR))
Expect(dstExternalCIDRNet).Should(Equal(tep.Status.RemoteNATExternalCIDR))
Expect(gwIP).Should(Equal(ipAddress2NoSubnet))
Expect(iFaceIndex).Should(BeNumerically("==", dummylink1.Attrs().Index))
})
Expand All @@ -492,7 +494,7 @@ var _ = Describe("Common", func() {
It("should return error", func() {
tepCopy := tep
tepCopy.Status.GatewayIP = notReachableIP
_, _, _, err := getRouteConfig(&tepCopy, gwIPCorrect)
_, _, _, _, err := getRouteConfig(&tepCopy, gwIPCorrect)
Expect(err).To(HaveOccurred())
Expect(err).Should(Equal(&errors.NoRouteFound{IPAddress: tepCopy.Status.GatewayIP}))
})
Expand Down
68 changes: 46 additions & 22 deletions pkg/liqonet/routing/directRouting.go
Expand Up @@ -46,26 +46,38 @@ func NewDirectRoutingManager(routingTableID int, podIP string) (Routing, error)
// Returns true if the routes have been configured, false if the routes are already configured.
// An error if something goes wrong and the routes can not be configured.
func (drm *DirectRoutingManager) EnsureRoutesPerCluster(tep *netv1alpha1.TunnelEndpoint) (bool, error) {
var routeAdd, policyRuleAdd, configured bool
var routePodCIDRAdd, routeExternalCIDRAdd, policyRulePodCIDRAdd, policyRuleExternalCIDRAdd, configured bool
clusterID := tep.Spec.ClusterID
// Extract and save route information from the given tep.
dstNet, gatewayIP, iFaceIndex, err := getRouteConfig(tep, drm.podIP)
dstPodCIDR, dstExternalCIDR, gatewayIP, iFaceIndex, err := getRouteConfig(tep, drm.podIP)
if err != nil {
return false, err
}
// Add policy routing rule for the given cluster.
klog.Infof("%s -> adding policy routing rule for destination {%s} to lookup routing table with ID {%d}", clusterID, dstNet, drm.routingTableID)
if policyRuleAdd, err = AddPolicyRoutingRule("", dstNet, drm.routingTableID); err != nil {
return policyRuleAdd, err
// Add policy routing rules for the given cluster.
klog.Infof("%s -> adding policy routing rule for destination {%s} to lookup routing table with ID {%d}",
clusterID, dstPodCIDR, drm.routingTableID)
if policyRulePodCIDRAdd, err = AddPolicyRoutingRule("", dstPodCIDR, drm.routingTableID); err != nil {
return policyRulePodCIDRAdd, err
}
klog.Infof("%s -> adding policy routing rule for destination {%s} to lookup routing table with ID {%d}",
clusterID, dstExternalCIDR, drm.routingTableID)
if policyRuleExternalCIDRAdd, err = AddPolicyRoutingRule("", dstExternalCIDR, drm.routingTableID); err != nil {
return policyRuleExternalCIDRAdd, err
}
// Add routes for the given cluster.
klog.Infof("%s -> adding route for destination {%s} with gateway {%s} in routing table with ID {%d}",
clusterID, dstPodCIDR, gatewayIP, drm.routingTableID)
routePodCIDRAdd, err = AddRoute(dstPodCIDR, gatewayIP, iFaceIndex, drm.routingTableID)
if err != nil {
return routePodCIDRAdd, err
}
// Add route for the given cluster.
klog.Infof("%s -> adding route for destination {%s} with gateway {%s} in routing table with ID {%d}",
clusterID, dstNet, gatewayIP, drm.routingTableID)
routeAdd, err = AddRoute(dstNet, gatewayIP, iFaceIndex, drm.routingTableID)
clusterID, dstExternalCIDR, gatewayIP, drm.routingTableID)
routeExternalCIDRAdd, err = AddRoute(dstExternalCIDR, gatewayIP, iFaceIndex, drm.routingTableID)
if err != nil {
return routeAdd, err
return routeExternalCIDRAdd, err
}
if routeAdd || policyRuleAdd {
if routePodCIDRAdd || routeExternalCIDRAdd || policyRulePodCIDRAdd || policyRuleExternalCIDRAdd {
configured = true
}
return configured, nil
Expand All @@ -76,26 +88,38 @@ func (drm *DirectRoutingManager) EnsureRoutesPerCluster(tep *netv1alpha1.TunnelE
// Returns true if the routes exist and have been deleted, false if nothing is removed.
// An error if something goes wrong and the routes can not be removed.
func (drm *DirectRoutingManager) RemoveRoutesPerCluster(tep *netv1alpha1.TunnelEndpoint) (bool, error) {
var routeDel, policyRuleDel, configured bool
var routePodCIDRDel, routeExternalCIDRDel, policyRulePodCIDRDel, policyRuleExternalCIDRDel, configured bool
clusterID := tep.Spec.ClusterID
// Extract and save route information from the given tep.
dstNet, gatewayIP, iFaceIndex, err := getRouteConfig(tep, drm.podIP)
dstPodCIDR, dstExternalCIDR, gatewayIP, iFaceIndex, err := getRouteConfig(tep, drm.podIP)
if err != nil {
return false, err
}
// Delete policy routing rule for the given cluster.
klog.Infof("%s -> deleting policy routing rule for destination {%s} to lookup routing table with ID {%d}", clusterID, dstNet, drm.routingTableID)
if policyRuleDel, err = DelPolicyRoutingRule("", dstNet, drm.routingTableID); err != nil {
return policyRuleDel, err
// Delete policy routing rules for the given cluster.
klog.Infof("%s -> deleting policy routing rule for destination {%s} to lookup routing table with ID {%d}",
clusterID, dstPodCIDR, drm.routingTableID)
if policyRulePodCIDRDel, err = DelPolicyRoutingRule("", dstPodCIDR, drm.routingTableID); err != nil {
return policyRulePodCIDRDel, err
}
klog.Infof("%s -> deleting policy routing rule for destination {%s} to lookup routing table with ID {%d}",
clusterID, dstExternalCIDR, drm.routingTableID)
if policyRuleExternalCIDRDel, err = DelPolicyRoutingRule("", dstExternalCIDR, drm.routingTableID); err != nil {
return policyRuleExternalCIDRDel, err
}
// Delete routes for the given cluster.
klog.Infof("%s -> deleting route for destination {%s} with gateway {%s} in routing table with ID {%d}",
clusterID, dstPodCIDR, gatewayIP, drm.routingTableID)
routePodCIDRDel, err = DelRoute(dstPodCIDR, gatewayIP, iFaceIndex, drm.routingTableID)
if err != nil {
return routePodCIDRDel, err
}
// Delete route for the given cluster.
klog.Infof("%s -> deleting route for destination {%s} with gateway {%s} in routing table with ID {%d}",
clusterID, dstNet, gatewayIP, drm.routingTableID)
routeDel, err = DelRoute(dstNet, gatewayIP, iFaceIndex, drm.routingTableID)
clusterID, dstExternalCIDR, gatewayIP, drm.routingTableID)
routeExternalCIDRDel, err = DelRoute(dstExternalCIDR, gatewayIP, iFaceIndex, drm.routingTableID)
if err != nil {
return routeDel, err
return routeExternalCIDRDel, err
}
if routeDel || policyRuleDel {
if routePodCIDRDel || routeExternalCIDRDel || policyRulePodCIDRDel || policyRuleExternalCIDRDel {
configured = true
}
return configured, nil
Expand Down
49 changes: 42 additions & 7 deletions pkg/liqonet/routing/directRouting_test.go
Expand Up @@ -23,7 +23,7 @@ var (
},
{
destinationNet: "10.101.0.0/16",
gatewayIP: "",
gatewayIP: "10.0.0.100",
iFaceIndex: 0,
routingTableID: routingTableIDDRM,
}}
Expand Down Expand Up @@ -79,7 +79,7 @@ var _ = Describe("DirectRouting", func() {
Expect(err).NotTo(BeNil())
})

It("route configuration fails while adding policy routing rule", func() {
It("route configuration fails while adding policy routing rule for PodCIDR", func() {
tepCopy := tep
tepCopy.Status.RemoteNATPodCIDR = ""
added, err := drm.EnsureRoutesPerCluster(&tepCopy)
Expand All @@ -91,6 +91,18 @@ var _ = Describe("DirectRouting", func() {
Expect(err).NotTo(BeNil())
})

It("route configuration fails while adding policy routing rule for ExternalCIDR", func() {
tepCopy := tep
tepCopy.Status.RemoteNATExternalCIDR = ""
added, err := drm.EnsureRoutesPerCluster(&tepCopy)
Expect(err).Should(Equal(&errors.WrongParameter{
Parameter: "fromSubnet and toSubnet",
Reason: errors.AtLeastOneValid,
}))
Expect(added).Should(BeFalse())
Expect(err).NotTo(BeNil())
})

It("route configuration fails while adding route", func() {
tepCopy := tep
tepCopy.Status.GatewayIP = ipAddress1NoSubnet
Expand All @@ -115,18 +127,25 @@ var _ = Describe("DirectRouting", func() {
Expect(err).ShouldNot(HaveOccurred())
Expect(added).Should(BeTrue())
// Get the inserted route
_, dstNet, err := net.ParseCIDR(tep.Status.RemoteNATPodCIDR)
_, dstPodCIDRNet, err := net.ParseCIDR(tep.Status.RemoteNATPodCIDR)
_, dstExternalCIDRNet, err := net.ParseCIDR(tep.Status.RemoteNATExternalCIDR)
Expect(err).ShouldNot(HaveOccurred())
routes, err := netlink.RouteListFiltered(netlink.FAMILY_V4, &netlink.Route{Dst: dstNet, Table: routingTableIDDRM}, netlink.RT_FILTER_DST|netlink.RT_FILTER_TABLE)
routes, err := netlink.RouteListFiltered(netlink.FAMILY_V4, &netlink.Route{Dst: dstPodCIDRNet, Table: routingTableIDDRM}, netlink.RT_FILTER_DST|netlink.RT_FILTER_TABLE)
Expect(err).ShouldNot(HaveOccurred())
Expect(routes[0].Dst.String()).Should(Equal(tep.Status.RemoteNATPodCIDR))
Expect(routes[0].Gw.String()).Should(Equal(tep.Status.GatewayIP))
routes, err = netlink.RouteListFiltered(netlink.FAMILY_V4, &netlink.Route{Dst: dstExternalCIDRNet, Table: routingTableIDDRM}, netlink.RT_FILTER_DST|netlink.RT_FILTER_TABLE)
Expect(err).ShouldNot(HaveOccurred())
Expect(routes[0].Dst.String()).Should(Equal(tep.Status.RemoteNATExternalCIDR))
Expect(routes[0].Gw.String()).Should(Equal(tep.Status.GatewayIP))
})

It("route already exists, should return false and nil", func() {
It("routes already exist, should return false and nil", func() {
tepCopy := tep
tepCopy.Status.RemoteNATPodCIDR = existingRoutesDRM[0].Dst.String()
tepCopy.Status.RemoteNATExternalCIDR = existingRoutesDRM[1].Dst.String()
tepCopy.Status.GatewayIP = existingRoutesDRM[0].Gw.String()
existingRoutesDRM[1].Gw = existingRoutesDRM[0].Gw
added, err := drm.EnsureRoutesPerCluster(&tepCopy)
Expect(err).ShouldNot(HaveOccurred())
Expect(added).Should(BeFalse())
Expand Down Expand Up @@ -159,7 +178,7 @@ var _ = Describe("DirectRouting", func() {
Expect(err).NotTo(BeNil())
})

It("fails to remove route configuration while removing policy routing rule", func() {
It("fails to remove route configuration while removing policy routing rule for PodCIDR", func() {
tepCopy := tep
tepCopy.Status.RemoteNATPodCIDR = ""
added, err := drm.RemoveRoutesPerCluster(&tepCopy)
Expand All @@ -170,6 +189,18 @@ var _ = Describe("DirectRouting", func() {
Expect(added).Should(BeFalse())
Expect(err).NotTo(BeNil())
})

It("fails to remove route configuration while removing policy routing rule for ExternalCIDR", func() {
tepCopy := tep
tepCopy.Status.RemoteNATExternalCIDR = ""
added, err := drm.RemoveRoutesPerCluster(&tepCopy)
Expect(err).Should(Equal(&errors.WrongParameter{
Parameter: "fromSubnet and toSubnet",
Reason: errors.AtLeastOneValid,
}))
Expect(added).Should(BeFalse())
Expect(err).NotTo(BeNil())
})
})

Context("when tep holds correct parameters", func() {
Expand All @@ -184,14 +215,18 @@ var _ = Describe("DirectRouting", func() {
It("route configuration should be correctly removed", func() {
tepCopy := tep
tepCopy.Status.RemoteNATPodCIDR = existingRoutesDRM[0].Dst.String()
tepCopy.Status.RemoteNATExternalCIDR = existingRoutesDRM[1].Dst.String()
tepCopy.Status.GatewayIP = existingRoutesDRM[0].Gw.String()
added, err := drm.RemoveRoutesPerCluster(&tepCopy)
Expect(err).ShouldNot(HaveOccurred())
Expect(added).Should(BeTrue())
// Try to get the remove route.
// Try to get removed routes.
routes, err := netlink.RouteListFiltered(netlink.FAMILY_V4, existingRoutesDRM[0], netlink.RT_FILTER_DST|netlink.RT_FILTER_TABLE)
Expect(err).ShouldNot(HaveOccurred())
Expect(len(routes)).Should(BeZero())
routes, err = netlink.RouteListFiltered(netlink.FAMILY_V4, existingRoutesDRM[1], netlink.RT_FILTER_DST|netlink.RT_FILTER_TABLE)
Expect(err).ShouldNot(HaveOccurred())
Expect(len(routes)).Should(BeZero())
})

It("route does not exist, should return false and nil", func() {
Expand Down
40 changes: 28 additions & 12 deletions pkg/liqonet/routing/gatewayRouting.go
Expand Up @@ -44,33 +44,49 @@ func NewGatewayRoutingManager(routingTableID int, tunnelDevice netlink.Link) (Ro
// Returns true if the routes have been configured, false if the routes are already configured.
// An error if something goes wrong and the routes can not be configured.
func (grm *GatewayRoutingManager) EnsureRoutesPerCluster(tep *netv1alpha1.TunnelEndpoint) (bool, error) {
var routeAdd bool
var routePodCIDRAdd, routeExternalCIDRAdd, configured bool
var err error
// Extract and save route information from the given tep.
_, dstNet := utils.GetPodCIDRS(tep)
// Add route for the given cluster.
routeAdd, err = AddRoute(dstNet, "", grm.tunnelDevice.Attrs().Index, grm.routingTableID)
_, dstPodCIDRNet := utils.GetPodCIDRS(tep)
_, dstExternalCIDRNet := utils.GetExternalCIDRS(tep)
// Add routes for the given cluster.
routePodCIDRAdd, err = AddRoute(dstPodCIDRNet, "", grm.tunnelDevice.Attrs().Index, grm.routingTableID)
if err != nil {
return routeAdd, err
return routePodCIDRAdd, err
}
return routeAdd, nil
routeExternalCIDRAdd, err = AddRoute(dstExternalCIDRNet, "", grm.tunnelDevice.Attrs().Index, grm.routingTableID)
if err != nil {
return routeExternalCIDRAdd, err
}
if routePodCIDRAdd || routeExternalCIDRAdd {
configured = true
}
return configured, nil
}

// RemoveRoutesPerCluster accepts as input a netv1alpha.tunnelendpoint.
// It deletes the routes if they do exist.
// Returns true if the routes exist and have been deleted, false if nothing is removed.
// An error if something goes wrong and the routes can not be removed.
func (grm *GatewayRoutingManager) RemoveRoutesPerCluster(tep *netv1alpha1.TunnelEndpoint) (bool, error) {
var routeDel bool
var routePodCIDRDel, routeExternalCIDRDel, configured bool
var err error
// Extract and save route information from the given tep.
_, dstNet := utils.GetPodCIDRS(tep)
// Delete route for the given cluster.
routeDel, err = DelRoute(dstNet, "", grm.tunnelDevice.Attrs().Index, grm.routingTableID)
_, dstPodCIDRNet := utils.GetPodCIDRS(tep)
_, dstExternalCIDRNet := utils.GetExternalCIDRS(tep)
// Delete routes for the given cluster.
routePodCIDRDel, err = DelRoute(dstPodCIDRNet, "", grm.tunnelDevice.Attrs().Index, grm.routingTableID)
if err != nil {
return routeDel, err
return routePodCIDRDel, err
}
routeExternalCIDRDel, err = DelRoute(dstExternalCIDRNet, "", grm.tunnelDevice.Attrs().Index, grm.routingTableID)
if err != nil {
return routeExternalCIDRDel, err
}
if routePodCIDRDel || routeExternalCIDRDel {
configured = true
}
return routeDel, nil
return configured, nil
}

// CleanRoutingTable stub function, as the gateway only operates in custom network namespace.
Expand Down

0 comments on commit 1b30550

Please sign in to comment.