Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 13 additions & 20 deletions go-controller/pkg/node/controllers/egressip/egressip.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/node/routemanager"
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/syncmap"
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/util"
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/util/egressip"
utilerrors "github.com/ovn-org/ovn-kubernetes/go-controller/pkg/util/errors"

corev1 "k8s.io/api/core/v1"
Expand Down Expand Up @@ -531,15 +532,15 @@ func (c *Controller) processEIP(eip *eipv1.EgressIP) (*eIPConfig, sets.Set[strin
if isValid := isEIPStatusItemValid(status, c.nodeName); !isValid {
continue
}
eIPNet, err := util.GetIPNetFullMask(status.EgressIP)
if err != nil {
ip := net.ParseIP(status.EgressIP)
if ip == nil {
return nil, selectedNamespaces, selectedPods, selectedNamespacesPodIPs,
fmt.Errorf("failed to generate mask for EgressIP %s IP %s: %v", eip.Name, status.EgressIP, err)
fmt.Errorf("failed to parse EgressIP %s IP %s", eip.Name, status.EgressIP)
}
if util.IsOVNNetwork(parsedNodeEIPConfig, eIPNet.IP) {
if util.IsOVNNetwork(parsedNodeEIPConfig, ip) {
continue
}
found, link, err := findLinkOnSameNetworkAsIP(eIPNet.IP, c.v4, c.v6)
found, link, err := findLinkOnSameNetworkAsIP(ip, c.v4, c.v6)
if err != nil {
return nil, selectedNamespaces, selectedPods, selectedNamespacesPodIPs,
fmt.Errorf("failed to find a network to host EgressIP %s IP %s: %v", eip.Name, status.EgressIP, err)
Expand All @@ -552,7 +553,7 @@ func (c *Controller) processEIP(eip *eipv1.EgressIP) (*eIPConfig, sets.Set[strin
if err != nil {
return nil, selectedNamespaces, selectedPods, selectedNamespacesPodIPs, fmt.Errorf("failed to list namespaces: %w", err)
}
isEIPV6 := utilnet.IsIPv6(eIPNet.IP)
isEIPV6 := utilnet.IsIPv6(ip)
for _, namespace := range namespaces {
selectedNamespaces.Insert(namespace.Name)
pods, err := c.listPodsByNamespaceAndSelector(namespace.Name, &eip.Spec.PodSelector)
Expand All @@ -577,13 +578,13 @@ func (c *Controller) processEIP(eip *eipv1.EgressIP) (*eIPConfig, sets.Set[strin
if selectedNamespacesPodIPs[namespace.Name] == nil {
selectedNamespacesPodIPs[namespace.Name] = make(map[ktypes.NamespacedName]*podIPConfigList)
}
selectedNamespacesPodIPs[namespace.Name][podNamespaceName] = generatePodConfig(ips, link, eIPNet, isEIPV6)
selectedNamespacesPodIPs[namespace.Name][podNamespaceName] = generatePodConfig(ips, link, ip, isEIPV6)
selectedPods.Insert(podNamespaceName)
}
}
// ensure at least one pod is selected before generating config
if len(selectedNamespacesPodIPs) > 0 {
eipSpecificConfig, err = generateEIPConfig(link, eIPNet, isEIPV6)
eipSpecificConfig, err = generateEIPConfig(link, ip, isEIPV6)
if err != nil {
return nil, selectedNamespaces, selectedPods, selectedNamespacesPodIPs,
fmt.Errorf("failed to generate EIP configuration for EgressIP %s IP %s: %v", eip.Name, status.EgressIP, err)
Expand All @@ -595,15 +596,15 @@ func (c *Controller) processEIP(eip *eipv1.EgressIP) (*eIPConfig, sets.Set[strin
return eipSpecificConfig, selectedNamespaces, selectedPods, selectedNamespacesPodIPs, nil
}

func generatePodConfig(podIPs []net.IP, link netlink.Link, eIPNet *net.IPNet, isEIPV6 bool) *podIPConfigList {
func generatePodConfig(podIPs []net.IP, link netlink.Link, eIP net.IP, isEIPV6 bool) *podIPConfigList {
newPodIPConfigs := newPodIPConfigList()
for _, podIP := range podIPs {
isPodIPv6 := utilnet.IsIPv6(podIP)
if isPodIPv6 != isEIPV6 {
continue
}
ipConfig := newPodIPConfig()
ipConfig.ipTableRule = generateIPTablesSNATRuleArg(podIP, isPodIPv6, link.Attrs().Name, eIPNet.IP.String())
ipConfig.ipTableRule = generateIPTablesSNATRuleArg(podIP, isPodIPv6, link.Attrs().Name, eIP.String())
ipConfig.ipRule = generateIPRule(podIP, isPodIPv6, link.Attrs().Index)
ipConfig.v6 = isPodIPv6
newPodIPConfigs.elems = append(newPodIPConfigs.elems, ipConfig)
Expand All @@ -612,14 +613,14 @@ func generatePodConfig(podIPs []net.IP, link netlink.Link, eIPNet *net.IPNet, is
}

// generateEIPConfig generates configuration that isn't related to any pod EIPs to support config of a single EIP
func generateEIPConfig(link netlink.Link, eIPNet *net.IPNet, isEIPV6 bool) (*eIPConfig, error) {
func generateEIPConfig(link netlink.Link, eIP net.IP, isEIPV6 bool) (*eIPConfig, error) {
eipConfig := newEIPConfig()
linkRoutes, err := generateRoutesForLink(link, isEIPV6)
if err != nil {
return nil, err
}
eipConfig.routes = linkRoutes
eipConfig.addr = getNetlinkAddress(eIPNet, link.Attrs().Index)
eipConfig.addr = egressip.GetNetlinkAddress(eIP, link.Attrs().Index)
return eipConfig, nil
}

Expand Down Expand Up @@ -1454,14 +1455,6 @@ func isLinkUp(flags string) bool {
return strings.Contains(flags, "up")
}

func getNetlinkAddress(addr *net.IPNet, ifindex int) *netlink.Addr {
return &netlink.Addr{
IPNet: addr,
Scope: int(netlink.SCOPE_UNIVERSE),
LinkIndex: ifindex,
}
}

// generateIPRules generates IP rules at a predefined priority for each pod IP with a custom routing table based
// from the links 'ifindex'
func generateIPRule(srcIP net.IP, isIPv6 bool, ifIndex int) netlink.Rule {
Expand Down
14 changes: 7 additions & 7 deletions go-controller/pkg/ovn/egressip_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5070,7 +5070,7 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations", func() {
}
_, node1Subnet, _ := net.ParseCIDR(v6Node1Subnet)
_, node2Subnet, _ := net.ParseCIDR(v6Node2Subnet)
egressIPServedPodsASv4, _ := buildEgressIPServedPodsAddressSets(nil, types.DefaultNetworkName, DefaultNetworkControllerName)
egressIPServedPodsASv4, _ := buildEgressIPServedPodsAddressSets(nil)
dynamicNeighRouters := "true"
if config.OVNKubernetesFeature.EnableInterconnect {
dynamicNeighRouters = "false"
Expand Down Expand Up @@ -5176,7 +5176,7 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations", func() {

expectedNatLogicalPort := "k8s-node2"

egressIPServedPodsASv4, _ := buildEgressIPServedPodsAddressSets(nil)
egressIPServedPodsASv4, _ = buildEgressIPServedPodsAddressSets(nil)

expectedDatabaseState := []libovsdbtest.TestData{
getReRoutePolicy(egressPod.Status.PodIP, "6", "reroute-UUID", node2LogicalRouterIPv6, eipExternalID),
Expand Down Expand Up @@ -5924,7 +5924,7 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations", func() {
egressNamespace := newNamespaceWithLabels(eipNamespace, egressPodLabel)
_, node1Subnet, _ := net.ParseCIDR(v6Node1Subnet)
_, node2Subnet, _ := net.ParseCIDR(v6Node2Subnet)
egressIPServedPodsASv4, _ := buildEgressIPServedPodsAddressSets(nil, types.DefaultNetworkName, DefaultNetworkControllerName)
egressIPServedPodsASv4, _ := buildEgressIPServedPodsAddressSets(nil)
dynamicNeighRouters := "true"
if config.OVNKubernetesFeature.EnableInterconnect {
dynamicNeighRouters = "false"
Expand Down Expand Up @@ -6040,7 +6040,7 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations", func() {
"stateless": "false",
},
}
egressIPServedPodsASv4, _ := buildEgressIPServedPodsAddressSets(nil)
egressIPServedPodsASv4, _ = buildEgressIPServedPodsAddressSets(nil)
expectedDatabaseState := []libovsdbtest.TestData{
&nbdb.LogicalRouterPolicy{
Priority: types.EgressIPReroutePriority,
Expand Down Expand Up @@ -10613,7 +10613,7 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations", func() {
gomega.Expect(err).NotTo(gomega.HaveOccurred())
})

ginkgo.DescribeTable(
ginkgotable.DescribeTable(
"DualStack cluster with single stack egressIP removes the correct snat rule when DisableSNATMultipleGWs=true",
func(
egressIP net.IP,
Expand Down Expand Up @@ -10884,11 +10884,11 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations", func() {
err := app.Run([]string{app.Name})
gomega.Expect(err).NotTo(gomega.HaveOccurred())
},
ginkgo.Entry(
ginkgotable.Entry(
"When EgressIP is ipv4",
net.ParseIP("192.168.126.101"),
),
ginkgo.Entry(
ginkgotable.Entry(
"When EgressIP is ipv6",
net.ParseIP("fc00:f853:0ccd:e793:ffff:ffff:ffff:0000"),
),
Expand Down
39 changes: 39 additions & 0 deletions go-controller/pkg/util/egressip/net.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package egressip

import (
"math"
"net"

"github.com/vishvananda/netlink"
"golang.org/x/sys/unix"

"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/util"
)

// GetNetlinkAddress returns a netlink address configured with specific
// egress ip parameters
func GetNetlinkAddress(ip net.IP, ifindex int) *netlink.Addr {
return &netlink.Addr{
IPNet: &net.IPNet{IP: ip, Mask: util.GetIPFullMask(ip)},
Flags: getNetlinkAddressFlag(ip),
Scope: int(netlink.SCOPE_UNIVERSE),
ValidLft: getNetlinkAddressValidLft(ip),
LinkIndex: ifindex,
}
}

func getNetlinkAddressFlag(ip net.IP) int {
// isV6?
if ip != nil && ip.To4() == nil && ip.To16() != nil {
return unix.IFA_F_NODAD
}
return 0
}

func getNetlinkAddressValidLft(ip net.IP) int {
// isV6?
if ip != nil && ip.To4() == nil && ip.To16() != nil {
return math.MaxUint32
}
return 0
}