Skip to content

Commit

Permalink
Merge pull request #3724 from flavio-fernandes/ovnic-static-routes
Browse files Browse the repository at this point in the history
ovn-ic: node update missing static routes
  • Loading branch information
dcbw committed Jul 6, 2023
2 parents a3dd7de + 980abd3 commit 137556d
Show file tree
Hide file tree
Showing 3 changed files with 170 additions and 14 deletions.
9 changes: 7 additions & 2 deletions go-controller/pkg/ovn/default_network_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -892,8 +892,13 @@ func (h *defaultNetworkControllerEventHandler) UpdateResource(oldObj, newObj int
return h.oc.addUpdateLocalNodeEvent(newNode, nodeSyncsParam)
} else {
_, syncZoneIC := h.oc.syncZoneICFailed.Load(newNode.Name)
// Check if the node moved from local zone to remote zone and if so syncZoneIC should be set to true
syncZoneIC = syncZoneIC || h.oc.isLocalZoneNode(oldNode)
// Check if the node moved from local zone to remote zone and if so syncZoneIC should be set to true.
// Also check if node subnet changed, so static routes are properly set
syncZoneIC = syncZoneIC || h.oc.isLocalZoneNode(oldNode) || nodeSubnetChanged(oldNode, newNode)
if syncZoneIC {
klog.Infof("Node %s in remote zone %s needs interconnect zone sync up.",
newNode.Name, util.GetNodeZone(newNode))
}
return h.oc.addUpdateRemoteNodeEvent(newNode, syncZoneIC)
}

Expand Down
72 changes: 68 additions & 4 deletions go-controller/pkg/ovn/master_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -912,9 +912,10 @@ var _ = ginkgo.Describe("Default network controller operations", func() {
)

const (
clusterIPNet string = "10.1.0.0"
clusterCIDR string = clusterIPNet + "/16"
vlanID = 1024
clusterIPNet string = "10.1.0.0"
clusterCIDR string = clusterIPNet + "/16"
clusterv6CIDR string = "aef0::/48"
vlanID = 1024
)

ginkgo.BeforeEach(func() {
Expand Down Expand Up @@ -1566,7 +1567,7 @@ var _ = ginkgo.Describe("Default network controller operations", func() {
gomega.Expect(err).NotTo(gomega.HaveOccurred())

// Ensure that the node's switch is eventually created once the annotations
// are reconiled by the network cluster controller
// are reconciled by the network cluster controller
newNodeLS := &nbdb.LogicalSwitch{Name: newNode.Name}
gomega.Eventually(func() error {
_, err := libovsdbops.GetLogicalSwitch(nbClient, newNodeLS)
Expand All @@ -1584,6 +1585,69 @@ var _ = ginkgo.Describe("Default network controller operations", func() {
})
gomega.Expect(err).NotTo(gomega.HaveOccurred())
})

ginkgo.It("reconciles node host subnets after single-stack to dual-stack upgrade", func() {
app.Action = func(ctx *cli.Context) error {
_, err := config.InitConfig(ctx, nil, nil)
gomega.Expect(err).NotTo(gomega.HaveOccurred())

gomega.Expect(config.IPv4Mode).To(gomega.BeTrue())
gomega.Expect(config.IPv6Mode).To(gomega.BeTrue())

newNodeIpv4Subnet := "10.1.1.0/24"
newNode := &v1.Node{
ObjectMeta: metav1.ObjectMeta{
Name: "newNode",
Annotations: map[string]string{
"k8s.ovn.org/node-subnets": fmt.Sprintf("{\"default\":[\"%s\"]}", newNodeIpv4Subnet),
"k8s.ovn.org/node-chassis-id": "2",
"k8s.ovn.org/node-gateway-router-lrp-ifaddr": "{\"ipv4\":\"100.64.0.2/16\"}",
},
},
}

_, err = kubeFakeClient.CoreV1().Nodes().Create(context.TODO(), newNode, metav1.CreateOptions{})
gomega.Expect(err).NotTo(gomega.HaveOccurred())

startFakeController(oc, wg)

// Simulate the ClusterManager reconciling the node annotations to dual-stack
newNode, err = kubeFakeClient.CoreV1().Nodes().Get(context.TODO(), newNode.Name, metav1.GetOptions{})
gomega.Expect(err).NotTo(gomega.HaveOccurred())
newNodeIpv6SubnetPrefix := "aef0:0:0:2::"
newNodeIpv6Subnet := newNodeIpv6SubnetPrefix + "2895/64"
newNode.Annotations["k8s.ovn.org/node-subnets"] = fmt.Sprintf("{\"default\":[\"%s\", \"%s\"]}", newNodeIpv4Subnet, newNodeIpv6Subnet)
_, err = kubeFakeClient.CoreV1().Nodes().Update(context.TODO(), newNode, metav1.UpdateOptions{})
gomega.Expect(err).NotTo(gomega.HaveOccurred())

// Ensure that the node's switch is eventually created once the annotations
// are reconciled by the network cluster controller
gomega.Eventually(func() bool {
newNodeLS, err := libovsdbops.GetLogicalSwitch(nbClient, &nbdb.LogicalSwitch{Name: newNode.Name})
if err != nil {
return false
}
if newNodeLS.OtherConfig["subnet"] != newNodeIpv4Subnet {
return false
}
if newNodeLS.OtherConfig["ipv6_prefix"] != newNodeIpv6SubnetPrefix {
return false
}
return true
}, 10).Should(gomega.BeTrue())

return nil
}

err := app.Run([]string{
app.Name,
"-cluster-subnets=" + clusterCIDR + "," + clusterv6CIDR,
"-k8s-service-cidr=10.96.0.0/16,fd00:10:96::/112",
"--init-gateways",
"--nodeport",
})
gomega.Expect(err).NotTo(gomega.HaveOccurred())
})
})

func nodeNoHostSubnetAnnotation() map[string]string {
Expand Down
103 changes: 95 additions & 8 deletions go-controller/pkg/ovn/zone_interconnect/zone_ic_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package zoneinterconnect
import (
"context"
"fmt"
"net"
"sort"

"github.com/onsi/ginkgo"
Expand Down Expand Up @@ -267,13 +268,14 @@ var _ = ginkgo.Describe("Zone Interconnect Operations", func() {
const (
clusterIPNet string = "10.1.0.0"
clusterCIDR string = clusterIPNet + "/16"
clusterv6CIDR string = "aef0::/48"
joinSubnetCIDR string = "100.64.0.0/16/19"
vlanID = 1024
)

ginkgo.BeforeEach(func() {
// Restore global default values before each testcase
//gomega.Expect(config.PrepareTestConfig()).To(gomega.Succeed())
gomega.Expect(config.PrepareTestConfig()).To(gomega.Succeed())

app = cli.NewApp()
app.Name = "test"
Expand Down Expand Up @@ -378,7 +380,7 @@ var _ = ginkgo.Describe("Zone Interconnect Operations", func() {
libovsdbOvnNBClient, libovsdbOvnSBClient, libovsdbCleanup, err = libovsdbtest.NewNBSBTestHarness(dbSetup)
gomega.Expect(err).NotTo(gomega.HaveOccurred())

err = createTransitSwitchPortBindings(libovsdbOvnSBClient, types.DefaultNetworkName, &testNode1, &testNode2, &testNode2)
err = createTransitSwitchPortBindings(libovsdbOvnSBClient, types.DefaultNetworkName, &testNode1, &testNode2, &testNode3)
gomega.Expect(err).NotTo(gomega.HaveOccurred())

zoneICHandler := NewZoneInterconnectHandler(&util.DefaultNetInfo{}, libovsdbOvnNBClient, libovsdbOvnSBClient)
Expand All @@ -399,6 +401,91 @@ var _ = ginkgo.Describe("Zone Interconnect Operations", func() {
gomega.Expect(err).NotTo(gomega.HaveOccurred())
})

ginkgo.It("Basic checks in dual-stack", func() {
app.Action = func(ctx *cli.Context) error {

dbSetup := libovsdbtest.TestSetup{
NBData: initialNBDB,
SBData: initialSBDB,
}

_, err := config.InitConfig(ctx, nil, nil)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
gomega.Expect(config.IPv4Mode).To(gomega.BeTrue())
gomega.Expect(config.IPv6Mode).To(gomega.BeTrue())
config.Kubernetes.HostNetworkNamespace = ""

var libovsdbOvnNBClient, libovsdbOvnSBClient libovsdbclient.Client
libovsdbOvnNBClient, libovsdbOvnSBClient, libovsdbCleanup, err = libovsdbtest.NewNBSBTestHarness(dbSetup)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
gomega.Expect(libovsdbOvnSBClient.Connected()).To(gomega.BeTrue())
gomega.Expect(libovsdbOvnNBClient.Connected()).To(gomega.BeTrue())

err = createTransitSwitchPortBindings(libovsdbOvnSBClient, types.DefaultNetworkName, &testNode1, &testNode2, &testNode3)
gomega.Expect(err).NotTo(gomega.HaveOccurred())

zoneICHandler := NewZoneInterconnectHandler(&util.DefaultNetInfo{}, libovsdbOvnNBClient, libovsdbOvnSBClient)
err = invokeICHandlerAddNodeFunction("global", zoneICHandler, &testNode1, &testNode2, &testNode3)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
err = checkInterconnectResources("global", types.DefaultNetworkName, libovsdbOvnNBClient, testNodesRouteInfo, &testNode1, &testNode2, &testNode3)
gomega.Expect(err).NotTo(gomega.HaveOccurred())

// Set annotations to include ipv6 to node3 (remote zone)
node3Ipv4Subnet := "10.244.4.0/24"
_, node3Ipv4SubnetNet, err := net.ParseCIDR(node3Ipv4Subnet)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
node3Ipv4SubnetPrefix := node3Ipv4SubnetNet.IP.String() + "/24"
node3TransitIpv4 := "168.254.0.4"
node3Ipv6Subnet := "aef0:0:0:4::2895/64"
_, node3Ipv6SubnetNet, err := net.ParseCIDR(node3Ipv6Subnet)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
node3Ipv6SubnetPrefix := node3Ipv6SubnetNet.IP.String() + "/64"
node3TransitIpv6 := "fd97::4"

testNode3.Annotations[ovnNodeSubnetsAnnotation] = "{\"default\":[\"" + node3Ipv4Subnet + "\", \"" + node3Ipv6Subnet + "\"]}"
testNode3.Annotations[ovnTransitSwitchPortAddrAnnotation] = "{\"ipv4\":\"" + node3TransitIpv4 + "/16\", \"ipv6\":\"" + node3TransitIpv6 + "/64\"}"

err = invokeICHandlerAddNodeFunction("global", zoneICHandler, &testNode3)
gomega.Expect(err).NotTo(gomega.HaveOccurred())

r := nbdb.LogicalRouter{
Name: getNetworkScopedName(types.DefaultNetworkName, types.OVNClusterRouter),
}
clusterRouter, err := libovsdbops.GetLogicalRouter(libovsdbOvnNBClient, &r)
gomega.Expect(err).NotTo(gomega.HaveOccurred())

// Make sure cluster router now has an static route for the remote node's ipv4 and ipv6
staticIpv4RouteFound := false
staticIpv6RouteFound := false
for _, srUUID := range clusterRouter.StaticRoutes {
newPredicate := func(item *nbdb.LogicalRouterStaticRoute) bool {
return item.UUID == srUUID
}
sr, err := libovsdbops.FindLogicalRouterStaticRoutesWithPredicate(libovsdbOvnNBClient, newPredicate)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
gomega.Expect(sr).Should(gomega.HaveLen(1), "The static route should have been found by uuid")
if sr[0].IPPrefix == node3Ipv4SubnetPrefix && sr[0].Nexthop == node3TransitIpv4 {
staticIpv4RouteFound = true
} else if sr[0].IPPrefix == node3Ipv6SubnetPrefix && sr[0].Nexthop == node3TransitIpv6 {
staticIpv6RouteFound = true
}
}
gomega.Expect(staticIpv4RouteFound).To(gomega.BeTrue())
gomega.Expect(staticIpv6RouteFound).To(gomega.BeTrue())
return nil
}

err := app.Run([]string{
app.Name,
"-cluster-subnets=" + clusterCIDR + "," + clusterv6CIDR,
"-k8s-service-cidr=10.96.0.0/16,fd00:10:96::/112",
"-init-cluster-manager",
"-zone-join-switch-subnets=" + joinSubnetCIDR,
"-enable-interconnect",
})
gomega.Expect(err).NotTo(gomega.HaveOccurred())
})

ginkgo.It("Change node zones", func() {
app.Action = func(ctx *cli.Context) error {
dbSetup := libovsdbtest.TestSetup{
Expand All @@ -414,7 +501,7 @@ var _ = ginkgo.Describe("Zone Interconnect Operations", func() {
libovsdbOvnNBClient, libovsdbOvnSBClient, libovsdbCleanup, err = libovsdbtest.NewNBSBTestHarness(dbSetup)
gomega.Expect(err).NotTo(gomega.HaveOccurred())

err = createTransitSwitchPortBindings(libovsdbOvnSBClient, types.DefaultNetworkName, &testNode1, &testNode2, &testNode2)
err = createTransitSwitchPortBindings(libovsdbOvnSBClient, types.DefaultNetworkName, &testNode1, &testNode2, &testNode3)
gomega.Expect(err).NotTo(gomega.HaveOccurred())

zoneICHandler := NewZoneInterconnectHandler(&util.DefaultNetInfo{}, libovsdbOvnNBClient, libovsdbOvnSBClient)
Expand Down Expand Up @@ -464,7 +551,7 @@ var _ = ginkgo.Describe("Zone Interconnect Operations", func() {
libovsdbOvnNBClient, libovsdbOvnSBClient, libovsdbCleanup, err = libovsdbtest.NewNBSBTestHarness(dbSetup)
gomega.Expect(err).NotTo(gomega.HaveOccurred())

err = createTransitSwitchPortBindings(libovsdbOvnSBClient, types.DefaultNetworkName, &testNode1, &testNode2, &testNode2)
err = createTransitSwitchPortBindings(libovsdbOvnSBClient, types.DefaultNetworkName, &testNode1, &testNode2, &testNode3)
gomega.Expect(err).NotTo(gomega.HaveOccurred())

zoneICHandler := NewZoneInterconnectHandler(&util.DefaultNetInfo{}, libovsdbOvnNBClient, libovsdbOvnSBClient)
Expand Down Expand Up @@ -579,7 +666,7 @@ var _ = ginkgo.Describe("Zone Interconnect Operations", func() {
libovsdbOvnNBClient, libovsdbOvnSBClient, libovsdbCleanup, err = libovsdbtest.NewNBSBTestHarness(dbSetup)
gomega.Expect(err).NotTo(gomega.HaveOccurred())

err = createTransitSwitchPortBindings(libovsdbOvnSBClient, types.DefaultNetworkName, &testNode1, &testNode2, &testNode2)
err = createTransitSwitchPortBindings(libovsdbOvnSBClient, types.DefaultNetworkName, &testNode1, &testNode2, &testNode3)
gomega.Expect(err).NotTo(gomega.HaveOccurred())

netInfo, err := util.NewNetInfo(&ovncnitypes.NetConf{NetConf: cnitypes.NetConf{Name: "blue"}, Topology: types.Layer3Topology})
Expand Down Expand Up @@ -617,7 +704,7 @@ var _ = ginkgo.Describe("Zone Interconnect Operations", func() {
libovsdbOvnNBClient, libovsdbOvnSBClient, libovsdbCleanup, err = libovsdbtest.NewNBSBTestHarness(dbSetup)
gomega.Expect(err).NotTo(gomega.HaveOccurred())

err = createTransitSwitchPortBindings(libovsdbOvnSBClient, types.DefaultNetworkName, &testNode1, &testNode2, &testNode2)
err = createTransitSwitchPortBindings(libovsdbOvnSBClient, types.DefaultNetworkName, &testNode1, &testNode2, &testNode3)
gomega.Expect(err).NotTo(gomega.HaveOccurred())

netInfo, err := util.NewNetInfo(&ovncnitypes.NetConf{NetConf: cnitypes.NetConf{Name: "blue"}, Topology: types.Layer3Topology})
Expand Down Expand Up @@ -675,7 +762,7 @@ var _ = ginkgo.Describe("Zone Interconnect Operations", func() {
},
}

err = createTransitSwitchPortBindings(libovsdbOvnSBClient, types.DefaultNetworkName, &testNode1, &testNode2, &testNode2)
err = createTransitSwitchPortBindings(libovsdbOvnSBClient, types.DefaultNetworkName, &testNode1, &testNode2, &testNode3)
gomega.Expect(err).NotTo(gomega.HaveOccurred())

zoneICHandler := NewZoneInterconnectHandler(&util.DefaultNetInfo{}, libovsdbOvnNBClient, libovsdbOvnSBClient)
Expand Down Expand Up @@ -763,7 +850,7 @@ var _ = ginkgo.Describe("Zone Interconnect Operations", func() {
},
}

err = createTransitSwitchPortBindings(libovsdbOvnSBClient, types.DefaultNetworkName, &testNode1, &testNode2, &testNode2)
err = createTransitSwitchPortBindings(libovsdbOvnSBClient, types.DefaultNetworkName, &testNode1, &testNode2, &testNode3)
gomega.Expect(err).NotTo(gomega.HaveOccurred())

zoneICHandler := NewZoneInterconnectHandler(&util.DefaultNetInfo{}, libovsdbOvnNBClient, libovsdbOvnSBClient)
Expand Down

0 comments on commit 137556d

Please sign in to comment.