diff --git a/contrib/kind.sh b/contrib/kind.sh index e5fc378074..fa2ae7a198 100755 --- a/contrib/kind.sh +++ b/contrib/kind.sh @@ -1072,11 +1072,16 @@ docker_create_second_interface() { } # run_script_in_container should be used when kind.sh is run nested in a container -# and makes sure the control-plane node is rechable by substituting 127.0.0.1 +# and makes sure the control-plane node is reachable by substituting 127.0.0.1 # with the control-plane container's IP run_script_in_container() { - local master_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' ${KIND_CLUSTER_NAME}-control-plane | head -n 1) - sed -i -- "s/server: .*/server: https:\/\/$master_ip:6443/g" $KUBECONFIG + if [ "$KIND_IPV4_SUPPORT" == true ]; then + local master_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' ${KIND_CLUSTER_NAME}-control-plane | head -n 1) + sed -i -- "s/server: .*/server: https:\/\/$master_ip:6443/g" $KUBECONFIG + else + local master_ipv6=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.GlobalIPv6Address}}{{end}}' ${KIND_CLUSTER_NAME}-control-plane | head -n 1) + sed -i -- "s/server: .*/server: https:\/\/[$master_ipv6]:6443/g" $KUBECONFIG + fi chmod a+r $KUBECONFIG } diff --git a/docs/features/multiple-networks/micro-segmentation-layer2-use-case.png b/docs/features/multiple-networks/micro-segmentation-layer2-use-case.png new file mode 100644 index 0000000000..7b07b6f0bd Binary files /dev/null and b/docs/features/multiple-networks/micro-segmentation-layer2-use-case.png differ diff --git a/docs/features/multiple-networks/micro-segmentation-localnet-use-case.png b/docs/features/multiple-networks/micro-segmentation-localnet-use-case.png new file mode 100644 index 0000000000..cce5216968 Binary files /dev/null and b/docs/features/multiple-networks/micro-segmentation-localnet-use-case.png differ diff --git a/docs/features/multiple-networks/multi-homing-use-case-layer2.png b/docs/features/multiple-networks/multi-homing-use-case-layer2.png new file mode 100644 index 0000000000..24801f49f6 Binary files /dev/null and b/docs/features/multiple-networks/multi-homing-use-case-layer2.png differ diff --git a/docs/features/multiple-networks/multi-homing-use-case-localnet.png b/docs/features/multiple-networks/multi-homing-use-case-localnet.png new file mode 100644 index 0000000000..31d323ca51 Binary files /dev/null and b/docs/features/multiple-networks/multi-homing-use-case-localnet.png differ diff --git a/docs/features/multiple-networks/multi-homing.md b/docs/features/multiple-networks/multi-homing.md index fd89716516..d01bd7ca9f 100644 --- a/docs/features/multiple-networks/multi-homing.md +++ b/docs/features/multiple-networks/multi-homing.md @@ -1,31 +1,81 @@ # Multihoming -A K8s pod with more than one network interface is said to be multi-homed. The -[Network Plumbing Working Group](https://github.com/k8snetworkplumbingwg/multi-net-spec) -has put forward a [standard](https://github.com/k8snetworkplumbingwg/multi-net-spec) -describing how to specify the configurations for additional network interfaces. +## Introduction +Multihoming allows the configuration of secondary-network interfaces for K8s pods. +OVN-Kubernetes secondary-network has three configurable topologies: layer 3, layer 2, or localnet. -There are several delegating plugins or meta-plugins (Multus, Genie) -implementing this standard. +- A layer 3 topology is a simplification of the topology for the cluster default network - but without egress. +- A layer 2 topology provides an isolated (no egress) cluster-wide layer2 network providing east-west traffic to the + cluster workloads. +- A localnet topology is based on layer 2 topology, but also allows connecting to an existent (configured) physical + network to provide north-south traffic to the workloads. -After a pod is scheduled on a particular Kubernetes node, kubelet will invoke -the delegating plugin to prepare the pod for networking. This meta-plugin will -then invoke the CNI responsible for setting up the pod's default cluster -network, and afterwards it iterates the list of additional attachments on the -pod, invoking the corresponding delegate CNI implementing the logic to attach -the pod to that particular network. +For layer 2 and localnet topologies, multihoming also allows IP features on secondary interfaces such as static IP +allocation and persistent IP addresses for virtualization workloads. -## Configuring secondary networks To allow pods to have multiple network interfaces, the user must provide the configurations specifying how to connect to these networks; these -configurations are defined in a CRD named `NetworkAttachmentDefinition`. +configurations are defined in a CRD named `NetworkAttachmentDefinition`, defined by +the [Kubernetes Network Custom Resource Definition De-facto Standard](https://github.com/k8snetworkplumbingwg/multi-net-spec). + +> [!NOTE] +> layer 2 and layer 3 topologies are overlays - thus, they do not need **any** previous physical network configuration. + +## Prerequisites +- [multus-cni](https://github.com/k8snetworkplumbingwg/multus-cni) + +## Motivation +Multihoming is essential when you need more than one network interface on your pods. This can be useful for various +use cases, such as virtual network functions (VNFs), firewalls, or virtualization (virt) where the default +cluster network might not be suitable. + +In OVN-K, multihoming supports several virt-specific features. These +include [persistent IP addresses for virtualization](#persistent-ip-addresses-for-virtualization-workloads) workloads, +ensuring that VMs retain their IP addresses even when they move across nodes. This enhances workload mobility and +minimizes disruptions. + +Multihoming is also compatible with the [multi-network policy](multi-network-policies.md) API, which can provide further security rules on the +traffic. + +## User-Stories +- As a Cluster-Admin, I want to configure secondary networks for specific pods so that I can enable + specialized/sensitive workloads with distinct network requirements. +- As a Cluster-Admin, I want to facilitate seamless live migration of VMs within so that I can maintain established TCP + connections and preserve VM IP configurations during migration. + +## User-Cases +- cluster-wide overlay network on layer 2: + In this case example, two VMs from different namespaces - VMA and VMC - are connected over a secondary-network. + VMB is not exposed to this traffic. + ![multi-homing-use-case-layer2](multi-homing-use-case-layer2.png) +- cluster-wide localnet network: + In this case example, Pod and VM workloads accessing a relational DB reachable via the physical network (i.e. deployed + outside Kubernetes). + ![multi-homing-use-case-localnet](multi-homing-use-case-localnet.png) + +## How to enable this feature on an OVN-Kubernetes cluster? +The `multi-network` feature must be enabled in the OVN-Kubernetes configuration. +Please use the `Feature Config` option `enable-multi-network` under `OVNKubernetesFeatureConfig` config to enable it. + +## Workflow Description +After a pod is scheduled on a particular Kubernetes node, kubelet will invoke +the meta-plugin installed on the cluster (such as [Multus](https://github.com/k8snetworkplumbingwg/multus-cni)) to +prepare the pod for networking. +The meta-plugin will invoke the CNI responsible for setting up the pod's default cluster network. +After that, the meta-plugin iterates the list of secondary networks, invoking the corresponding CNI implementing +the logic to attach the pod to that particular secondary-network. The CNI will use the details specified on +the `network-attachment-definition` in order to do that. -Below you will find example attachment configurations for each of the current -topologies OVN-K allows for secondary networks. +> [!NOTE] +> networks are **not** namespaced - i.e. creating multiple `network-attachment-definition`s with different + configurations pointing at the same network (same `NetConf.Name` attribute) is **not** supported. -**NOTE**: -- networks are **not** namespaced - i.e. creating multiple - `network-attachment-definition`s with different configurations pointing at the - same network (same `NetConf.Name` attribute) is **not** supported. +## Implementation Details +## User facing API Changes +There are no user facing API Changes. + +## OVN-Kubernetes Implementation Details +Below you will find example attachment configurations for each of the current topologies OVN-K allows for secondary +networks. ### Routed - layer 3 - topology This topology is a simplification of the topology for the cluster default @@ -47,7 +97,7 @@ spec: config: |2 { "cniVersion": "1.0.0", - "name": "l3-network", + "name": "tenantblue", "type": "ovn-k8s-cni-overlay", "topology":"layer3", "subnets": "10.128.0.0/16/24", @@ -56,7 +106,8 @@ spec: } ``` -#### Network Configuration reference +#### Network Configuration reference: + - `name` (string, required): the name of the network. This attribute is **not** namespaced. - `type` (string, required): "ovn-k8s-cni-overlay". - `topology` (string, required): "layer3". @@ -66,11 +117,13 @@ spec: - `netAttachDefName` (string, required): must match `/` of the surrounding object. -**NOTE** -- the `subnets` attribute indicates both the subnet across the cluster, and per node. +> [!NOTE] +> the `subnets` attribute indicates both the subnet across the cluster, and per node. The example above means you have a /16 subnet for the network, but each **node** has a /24 subnet. -- routed - layer3 - topology networks **only** allow for east/west traffic. + +> [!NOTE] +> routed - layer3 - topology networks **only** allow for east/west traffic. ### Switched - layer 2 - topology This topology interconnects the workloads via a cluster-wide logical switch. @@ -88,7 +141,7 @@ spec: config: |2 { "cniVersion": "1.0.0", - "name": "l2-network", + "name": "tenantyellow", "type": "ovn-k8s-cni-overlay", "topology":"layer2", "subnets": "10.100.200.0/24", @@ -111,15 +164,17 @@ spec: These IPs will be removed from the assignable IP pool, and never handed over to the pods. - `allowPersistentIPs` (boolean, optional): persist the OVN Kubernetes assigned - IP addresses in a `ipamclaims.k8s.cni.cncf.io` object. This IP addresses will - be reused by other pods if requested. Useful for KubeVirt VMs. Only makes - sense if the `subnets` attribute is also defined. + IP addresses in a `ipamclaims.k8s.cni.cncf.io` object. This IP addresses will + be reused by other pods if requested. Useful for KubeVirt VMs. Only makes + sense if the `subnets` attribute is also defined. -**NOTE** -- when the subnets attribute is omitted, the logical switch implementing the +> [!NOTE] +> when the subnets attribute is omitted, the logical switch implementing the network will only provide layer 2 communication, and the users must configure IPs for the pods. Port security will only prevent MAC spoofing. -- switched - layer2 - secondary networks **only** allow for east/west traffic. + +> [!NOTE] +> switched - layer2 - secondary networks **only** allow for east/west traffic. ### Switched - localnet - topology This topology interconnects the workloads via a cluster-wide logical switch to @@ -138,7 +193,7 @@ spec: config: |2 { "cniVersion": "1.0.0", - "name": "localnet-network", + "name": "tenantblack", "type": "ovn-k8s-cni-overlay", "topology":"localnet", "subnets": "202.10.130.112/28", @@ -166,71 +221,21 @@ localnet network. to the pods. - `vlanID` (integer, optional): assign VLAN tag. Defaults to none. - `allowPersistentIPs` (boolean, optional): persist the OVN Kubernetes assigned - IP addresses in a `ipamclaims.k8s.cni.cncf.io` object. This IP addresses will - be reused by other pods if requested. Useful for KubeVirt VMs. Only makes - sense if the `subnets` attribute is also defined. -- `physicalNetworkName` (string, optional): the name of the physical network to - which the OVN overlay will connect. When omitted, it will default to the value - of the localnet network `name`. - -**NOTE** -- when the subnets attribute is omitted, the logical switch implementing the + IP addresses in a `ipamclaims.k8s.cni.cncf.io` object. This IP addresses will + be reused by other pods if requested. Useful for KubeVirt VMs. Only makes + sense if the `subnets` attribute is also defined. + +> [!NOTE] +> when the subnets attribute is omitted, the logical switch implementing the network will only provide layer 2 communication, and the users must configure IPs for the pods. Port security will only prevent MAC spoofing. -#### Sharing the same physical network mapping -To prevent the admin from having to reconfigure the cluster nodes whenever they -want to - let's say - add a VLAN, OVN-Kubernetes allows multiple network -overlays to re-use the same physical network mapping. - -To do this, the cluster admin would provision two different networks (with -different VLAN tags) using the **same** physical network name. Please check the -example below for an example of this configuration: -```yaml ---- -apiVersion: k8s.cni.cncf.io/v1 -kind: NetworkAttachmentDefinition -metadata: - name: bluenet - namespace: test -spec: - config: | - { - "cniVersion": "0.3.1", - "name": "tenantblue", - "type": "ovn-k8s-cni-overlay", - "topology": "localnet", - "netAttachDefName": "test/bluenet", - "vlanID": 4000, - "physicalNetworkName": "physnet" - } ---- -apiVersion: k8s.cni.cncf.io/v1 -kind: NetworkAttachmentDefinition -metadata: - name: isolatednet - namespace: test -spec: - config: | - { - "cniVersion": "0.3.1", - "name": "sales", - "type": "ovn-k8s-cni-overlay", - "topology": "localnet", - "netAttachDefName": "test/isolatednet", - "vlanID": 1234, - "physicalNetworkName": "physnet" - } -``` - -> [!WARNING] -> Keep in mind OVN-Kubernetes does **not** validate the physical network -> configurations in any way: the admin must ensure these configurations are -> holistically healthy - e.g. the defined subnets do not overlap, the MTUs make -> sense, etc. +> [!NOTE] +> updates to the network specification require the attached workloads restart. All the network-attachment-definitions + pointing to the same network must have a consistent configuration, and then workloads must be restarted. -## Pod configuration -The user must specify the secondary network attachments via the +### Setting a secondary-network on the pod +The user must specify the secondary-network attachments via the `k8s.v1.cni.cncf.io/networks` annotation. The following example provisions a pod with two secondary attachments, one for @@ -256,8 +261,8 @@ spec: ### Setting static IP addresses on a pod The user can specify attachment parameters via -[network-selection-elements](https://github.com/k8snetworkplumbingwg/network-attachment-definition-client/blob/63033d5c63d1cf56f924a5454c8f2ac444b6736d/pkg/apis/k8s.cni.cncf.io/v1/types.go#L137) -, namely IP, MAC, and interface name. +[network-selection-elements](https://github.com/k8snetworkplumbingwg/network-attachment-definition-client/blob/63033d5c63d1cf56f924a5454c8f2ac444b6736d/pkg/apis/k8s.cni.cncf.io/v1/types.go#L137), +namely IP, MAC, and interface name. Refer to the following yaml for an example on how to request a static IP for a pod, a MAC address, and specify the pod interface name. @@ -288,13 +293,15 @@ spec: name: agnhost-container ``` -**NOTE:** -- the user can specify the IP address for a pod's secondary attachment +> [!NOTE] +> the user can specify the IP address for a pod's secondary attachment **only** for an L2 or localnet attachment. -- specifying a static IP address for the pod is only possible when the + +> [!NOTE] +> specifying a static IP address for the pod is only possible when the attachment configuration does **not** feature subnets. -## Persistent IP addresses for virtualization workloads +### Persistent IP addresses for virtualization workloads OVN-Kubernetes provides persistent IP addresses for virtualization workloads, allowing VMs to have the same IP addresses when they migrate, when they restart, and when they stop, the resume operation. @@ -305,10 +312,11 @@ other network knobs, all NADs pointing to the same network **must** feature the same configuration - i.e. all NADs in the network must either allow (or reject) persistent IPs. -The client application (which creates the VM, and manages its lifecycle) is +The client application (which creates the +VM, and manages its lifecycle) is responsible for creating the `ipamclaims.k8s.cni.cncf.io` object, and point to -it in the network selection element upon pod creation; OVN-Kubernetes will then -persist the IP addresses it has allocated the pod in the `IPAMClaim`. This flow +it in the network selection element upon pod creation; +OVN-Kubernetes will then persist the IP addresses it has allocated the pod in the `IPAMClaim`. This flow is portrayed in the sequence diagram below. ```mermaid @@ -375,16 +383,19 @@ For both ipv4 and ipv6 the following parameters are configured using DHCP or RAs - mtu (taken from network attachment definition) ### Configuring dns server -By default the DHCP server at ovn-kuberntes will configure the kubernetes +By default, the DHCP server at ovn-kubernetes will configure the kubernetes default dns service `kube-system/kube-dns` as the name server. This can be overridden with the following command line options: - dns-service-namespace - dns-service-name ## Limitations -OVN-K currently does **not** support: +OVN-Kubernetes currently does **not** support: + - the same attachment configured multiple times in the same pod - i.e. `k8s.v1.cni.cncf.io/networks: l3-network,l3-network` is invalid. - updates to the network selection elements lists - i.e. `k8s.v1.cni.cncf.io/networks` annotation +- external IPAM - i.e. the user can't define the IPAM attribute in the configuration. They must use the subnets + attribute. - IPv6 link local addresses not derived from the MAC address as described in RFC 2373, like Privacy Extensions defined by RFC 4941, or the Opaque Identifier generation methods defined in RFC 7217. diff --git a/docs/features/multiple-networks/multi-network-policies.md b/docs/features/multiple-networks/multi-network-policies.md index 5033b36fb2..84273eaede 100644 --- a/docs/features/multiple-networks/multi-network-policies.md +++ b/docs/features/multiple-networks/multi-network-policies.md @@ -1,10 +1,41 @@ # MultiNetworkPolicies -OVN-Kubernetes implements native support for -[multi-networkpolicy](https://github.com/k8snetworkplumbingwg/multi-networkpolicy), -an API providing +## Introduction +[multi-networkpolicy](https://github.com/k8snetworkplumbingwg/multi-networkpolicy) provides [network policy](https://kubernetes.io/docs/concepts/services-networking/network-policies/) -features for secondary networks. +features for secondary networks, and allows enhanced traffic security. +## Motivation +In Kubernetes the paradigm is that by default, all pods can reach other pods, and security is provided by +implementing [Network Policy](https://kubernetes.io/docs/concepts/services-networking/network-policies/). +MultiNetworkPolicies provide the same security solution to secondary interfaces. +For users seeking network security using multi-homing - traffic restrictions based on user network configuration is a +recommended practice. + +For example, by defining policies that specify which services a workload can access, they mitigate supply chain attacks +and reduce the risk of lateral movement. +Even if a component is compromised, it won’t be able to jeopardize other components of the system. + +## User-Stories +As a project administrator, I want to enforce network policies that must be adhered to by all workloads on +my namespace. This will secure my namespace’s network traffic. + +## User-case +- Limit access between workloads running on the cluster connected on a flat layer2 topology: + In this case example, VMA is a data processor, VMC is a real-time data producer, and VMB is a monitoring and alerting unit. + The data producer (VMC) can send data to the data processor (VMA), but cannot communicate with the monitoring unit (VMB). + The data processor (VMA) can send alerts and metrics to the monitoring unit (VMB). + ![multi-homing-use-case-layer2](multi-homing-use-case-layer2.png) + ![micro-segmentation-use-case](micro-segmentation-layer2-use-case.png) +- Limit access to a database set outside the cluster, connected to VM and Pod workloads via localnet overlay network: + In this case example, only the VM has access to the database. + ![multi-homing-use-case-localnet](multi-homing-use-case-localnet.png) + ![micro-segmentation-use-case](micro-segmentation-localnet-use-case.png) + +## How to enable this feature on an OVN-Kubernetes cluster? +The `multi-network-policies` feature must be enabled in the OVN-Kubernetes configuration. +Please use the `Feature Config` option `enable-multi-network` under `OVNKubernetesFeatureConfig` config to enable it. + +## Workflow Description To configure pod isolation, the user must: - provision a `network-attachment-definition`. - provision a `MultiNetworkPolicy` indicating to which secondary networks it @@ -12,9 +43,8 @@ To configure pod isolation, the user must: [policy-for](https://github.com/k8snetworkplumbingwg/multi-networkpolicy#policy-for-annotation) annotation. -**NOTE:** the `OVN_MULTI_NETWORK_ENABLE` config flag must be enabled. - Please refer to the following example: + ```yaml --- apiVersion: k8s.cni.cncf.io/v1 @@ -24,7 +54,7 @@ metadata: spec: config: '{ "cniVersion": "0.4.0", - "name": "tenant-blue", + "name": "tenant-blue-net", "netAttachDefName": "default/tenant-blue", "topology": "layer2", "type": "ovn-k8s-cni-overlay", @@ -57,7 +87,11 @@ Please note the `MultiNetworkPolicy` has the **exact same** API of the native `networking.k8s.io/v1` `NetworkPolicy`object; check its documentation for more information. -**Note:** `net-attach-def`s referred to by the `k8s.v1.cni.cncf.io/policy-for` +> [!NOTE] +> `net-attach-def`s referred to by the `k8s.v1.cni.cncf.io/policy-for` annotation without the subnet attribute defined are possible if the policy **only features** `ipBlock` peers. If the `net-attach-def` features the -`subnet` attribute, it can also feature `namespaceSelectors` and `podSelectors`. \ No newline at end of file +`subnet` attribute, it can also feature `namespaceSelectors` and `podSelectors`. + +## User facing API Changes +There are no user facing API Changes. diff --git a/go-controller/observability-lib/model/network_event.go b/go-controller/observability-lib/model/network_event.go index 00fb19fcfd..3a10bdbcf3 100644 --- a/go-controller/observability-lib/model/network_event.go +++ b/go-controller/observability-lib/model/network_event.go @@ -2,9 +2,30 @@ package model import ( "fmt" +) + +const ( + // Constants are duplicated to minimize dependencies + // When adding constants here, add them in network_event_test.go too + + // libovsdb constants: see also github.com/ovn-org/ovn-kubernetes/go-controller/pkg/libovsdb/ops + egressFirewallOwnerType = "EgressFirewall" + adminNetworkPolicyOwnerType = "AdminNetworkPolicy" + baselineAdminNetworkPolicyOwnerType = "BaselineAdminNetworkPolicy" + networkPolicyOwnerType = "NetworkPolicy" + multicastNamespaceOwnerType = "MulticastNS" + multicastClusterOwnerType = "MulticastCluster" + netpolNodeOwnerType = "NetpolNode" + netpolNamespaceOwnerType = "NetpolNamespace" + udnIsolationOwnerType = "UDNIsolation" - libovsdbops "github.com/ovn-org/ovn-kubernetes/go-controller/pkg/libovsdb/ops" - "github.com/ovn-org/ovn-kubernetes/go-controller/pkg/nbdb" + // nbdb constants: see also github.com/ovn-org/ovn-kubernetes/go-controller/pkg/nbdb + aclActionAllow = "allow" + aclActionAllowRelated = "allow-related" + aclActionAllowStateless = "allow-stateless" + aclActionDrop = "drop" + aclActionReject = "reject" + aclActionPass = "pass" ) type NetworkEvent interface { @@ -23,38 +44,38 @@ type ACLEvent struct { func (e *ACLEvent) String() string { var action string switch e.Action { - case nbdb.ACLActionAllow, nbdb.ACLActionAllowRelated, nbdb.ACLActionAllowStateless: + case aclActionAllow, aclActionAllowRelated, aclActionAllowStateless: action = "Allowed" - case nbdb.ACLActionDrop: + case aclActionDrop: action = "Dropped" - case nbdb.ACLActionPass: + case aclActionPass: action = "Delegated to network policy" default: action = "Action " + e.Action } var msg string switch e.Actor { - case libovsdbops.AdminNetworkPolicyOwnerType: + case adminNetworkPolicyOwnerType: msg = fmt.Sprintf("admin network policy %s, direction %s", e.Name, e.Direction) - case libovsdbops.BaselineAdminNetworkPolicyOwnerType: + case baselineAdminNetworkPolicyOwnerType: msg = fmt.Sprintf("baseline admin network policy %s, direction %s", e.Name, e.Direction) - case libovsdbops.MulticastNamespaceOwnerType: + case multicastNamespaceOwnerType: msg = fmt.Sprintf("multicast in namespace %s, direction %s", e.Namespace, e.Direction) - case libovsdbops.MulticastClusterOwnerType: + case multicastClusterOwnerType: msg = fmt.Sprintf("cluster multicast policy, direction %s", e.Direction) - case libovsdbops.NetpolNodeOwnerType: + case netpolNodeOwnerType: msg = fmt.Sprintf("default allow from local node policy, direction %s", e.Direction) - case libovsdbops.NetworkPolicyOwnerType: + case networkPolicyOwnerType: if e.Namespace != "" { msg = fmt.Sprintf("network policy %s in namespace %s, direction %s", e.Name, e.Namespace, e.Direction) } else { msg = fmt.Sprintf("network policy %s, direction %s", e.Name, e.Direction) } - case libovsdbops.NetpolNamespaceOwnerType: + case netpolNamespaceOwnerType: msg = fmt.Sprintf("network policies isolation in namespace %s, direction %s", e.Namespace, e.Direction) - case libovsdbops.EgressFirewallOwnerType: + case egressFirewallOwnerType: msg = fmt.Sprintf("egress firewall in namespace %s", e.Namespace) - case libovsdbops.UDNIsolationOwnerType: + case udnIsolationOwnerType: msg = fmt.Sprintf("UDN isolation of type %s", e.Name) } return fmt.Sprintf("%s by %s", action, msg) diff --git a/go-controller/observability-lib/model/network_event_test.go b/go-controller/observability-lib/model/network_event_test.go new file mode 100644 index 0000000000..7b3091f757 --- /dev/null +++ b/go-controller/observability-lib/model/network_event_test.go @@ -0,0 +1,35 @@ +package model + +import ( + "testing" + + libovsdbops "github.com/ovn-org/ovn-kubernetes/go-controller/pkg/libovsdb/ops" + "github.com/ovn-org/ovn-kubernetes/go-controller/pkg/nbdb" +) + +var mapping = map[string]string{ + egressFirewallOwnerType: libovsdbops.EgressFirewallOwnerType, + adminNetworkPolicyOwnerType: libovsdbops.AdminNetworkPolicyOwnerType, + baselineAdminNetworkPolicyOwnerType: libovsdbops.BaselineAdminNetworkPolicyOwnerType, + networkPolicyOwnerType: libovsdbops.NetworkPolicyOwnerType, + multicastNamespaceOwnerType: libovsdbops.MulticastNamespaceOwnerType, + multicastClusterOwnerType: libovsdbops.MulticastClusterOwnerType, + netpolNodeOwnerType: libovsdbops.NetpolNodeOwnerType, + netpolNamespaceOwnerType: libovsdbops.NetpolNamespaceOwnerType, + udnIsolationOwnerType: libovsdbops.UDNIsolationOwnerType, + aclActionAllow: nbdb.ACLActionAllow, + aclActionAllowRelated: nbdb.ACLActionAllowRelated, + aclActionAllowStateless: nbdb.ACLActionAllowStateless, + aclActionDrop: nbdb.ACLActionDrop, + aclActionPass: nbdb.ACLActionPass, + aclActionReject: nbdb.ACLActionReject, +} + +// Protects from potential future renaming in ovn/ovs constants, since all constants are duplicated here +func TestConstantsMatch(t *testing.T) { + for k, v := range mapping { + if k != v { + t.Fatalf("Constant %s does not match %s", k, v) + } + } +} diff --git a/go-controller/pkg/clustermanager/egressip_controller_test.go b/go-controller/pkg/clustermanager/egressip_controller_test.go index 0573f7e17d..5bf9bc752f 100644 --- a/go-controller/pkg/clustermanager/egressip_controller_test.go +++ b/go-controller/pkg/clustermanager/egressip_controller_test.go @@ -1256,7 +1256,39 @@ var _ = ginkgo.Describe("OVN cluster-manager EgressIP Operations", func() { gomega.Expect(fakeClusterManagerOVN.eIPC.nodeAllocator.cache).To(gomega.HaveKey(node2.Name)) gomega.Eventually(getEgressIPStatusLen(egressIPName)).Should(gomega.Equal(0)) - gomega.Eventually(fakeClusterManagerOVN.fakeRecorder.Events).Should(gomega.HaveLen(3)) + // event1 triggered during node1 add for the existing EIP and event2 is triggered during node2 add for the existing EIP + /*I0212 20:22:37.636573 1837759 egressip_controller.go:723] Egress node: node1 about to be initialized + I0212 20:22:37.636670 1837759 obj_retry.go:512] Add event received for *factory.egressNode node2 + I0212 20:22:37.636757 1837759 egressip_controller.go:723] Egress node: node2 about to be initialized + I0212 20:22:37.636855 1837759 egressip_controller.go:1173] Current assignments are: map[] + I0212 20:22:37.636865 1837759 egressip_controller.go:1175] Will attempt assignment for egress IP: 192.168.126.51 + E0212 20:22:37.636909 1837759 egressip_controller.go:1190] Egress IP: 192.168.126.51 address is already assigned on an interface on node node2 + I0212 20:22:37.636919 1837759 obj_retry.go:551] Creating *factory.egressNode node2 took: 217.968µs + I0212 20:22:37.638850 1837759 egressip_controller.go:1173] Current assignments are: map[] + I0212 20:22:37.639675 1837759 egressip_controller.go:1175] Will attempt assignment for egress IP: 192.168.126.51 + E0212 20:22:37.639753 1837759 egressip_controller.go:1190] Egress IP: 192.168.126.51 address is already assigned on an interface on node node2 + I0212 20:22:37.639776 1837759 obj_retry.go:551] Creating *factory.egressNode node1 took: 3.316342ms*/ + + // event3 trigged from syncEgressIPMarkAllocator called during WatchEgressIP starter syncFunc and + // event4 is triggered on the actual EIP add reconcile + /*I0212 20:22:37.639894 1837759 egressip_controller.go:1729] Patching status on EgressIP egressip: [{add /metadata/annotations map[k8s.ovn.org/egressip-mark:50000]}] + I0212 20:22:37.641594 1837759 obj_retry.go:512] Add event received for *v1.EgressIP egressip + I0212 20:22:37.641635 1837759 egressip_controller.go:1173] Current assignments are: map[] + I0212 20:22:37.641641 1837759 egressip_controller.go:1175] Will attempt assignment for egress IP: 192.168.126.51 + E0212 20:22:37.641664 1837759 egressip_controller.go:1190] Egress IP: 192.168.126.51 address is already assigned on an interface on node node2 + I0212 20:22:37.641670 1837759 obj_retry.go:551] Creating *v1.EgressIP egressip took: 53.241µs + I0212 20:22:37.643003 1837759 factory.go:1322] Added *v1.EgressIP event handler 2 + I0212 20:22:37.643123 1837759 obj_retry.go:568] Update event received for resource *v1.EgressIP, old object is equal to new: false + I0212 20:22:37.643154 1837759 obj_retry.go:620] Update event received for *v1.EgressIP egressip + I0212 20:22:37.643187 1837759 egressip_controller.go:1173] Current assignments are: map[] + I0212 20:22:37.643205 1837759 egressip_controller.go:1175] Will attempt assignment for egress IP: 192.168.126.51 + E0212 20:22:37.643254 1837759 egressip_controller.go:1190] Egress IP: 192.168.126.51 address is already assigned on an interface on node node2*/ + gomega.Eventually(fakeClusterManagerOVN.fakeRecorder.Events).Should(gomega.HaveLen(4)) + for i := 0; i < 4; i++ { + recordedEvent := <-fakeClusterManagerOVN.fakeRecorder.Events + gomega.Expect(recordedEvent).To(gomega.ContainSubstring( + "EgressIPConflict Egress IP egressip with IP 192.168.126.51 is conflicting with a host (node2) IP address and will not be assigned")) + } return nil } diff --git a/go-controller/pkg/cni/cni.go b/go-controller/pkg/cni/cni.go index 10c09897d6..5f1d8e2fab 100644 --- a/go-controller/pkg/cni/cni.go +++ b/go-controller/pkg/cni/cni.go @@ -101,7 +101,8 @@ func (pr *PodRequest) checkOrUpdatePodUID(pod *kapi.Pod) error { pr.PodUID = string(pod.UID) } else if string(pod.UID) != pr.PodUID { // Exit early if the pod was deleted and recreated already - return fmt.Errorf("pod deleted before sandbox %v operation began", pr.Command) + return fmt.Errorf("pod deleted before sandbox %v operation began. Request Pod UID %s is different from "+ + "the Pod UID (%s) retrieved from the informer/API", pr.Command, pr.PodUID, pod.UID) } return nil } diff --git a/go-controller/pkg/node/gateway_init_linux_test.go b/go-controller/pkg/node/gateway_init_linux_test.go index f4c3142096..8d4b4800f5 100644 --- a/go-controller/pkg/node/gateway_init_linux_test.go +++ b/go-controller/pkg/node/gateway_init_linux_test.go @@ -950,6 +950,8 @@ func localGatewayInterfaceTest(app *cli.App, testNS ns.NetNS, const mtu string = "1234" const clusterCIDR string = "10.1.0.0/16" config.Gateway.DisableForwarding = true + // Make this larger-than-default, so it makes sense for the UDN case + config.Gateway.V4MasqueradeSubnet = "169.254.169.0/24" if len(eth0GWIP) > 0 { // And a default route @@ -1345,9 +1347,9 @@ OFPT_GET_CONFIG_REPLY (xid=0x4): frags=normal miss_send_len=0` "-j OVN-KUBE-UDN-MASQUERADE", ) expectedTables["nat"]["OVN-KUBE-UDN-MASQUERADE"] = append(expectedTables["nat"]["OVN-KUBE-UDN-MASQUERADE"], - "-s 169.254.169.2/29 -j RETURN", // this guarantees we don't SNAT default network masqueradeIPs + "-s 169.254.169.0/29 -j RETURN", // this guarantees we don't SNAT default network masqueradeIPs "-d 172.16.1.0/24 -j RETURN", // this guarantees we don't SNAT service traffic - "-s 169.254.169.0/29 -j MASQUERADE", // this guarantees we SNAT all UDN MasqueradeIPs traffic leaving the node + "-s 169.254.169.0/24 -j MASQUERADE", // this guarantees we SNAT all UDN MasqueradeIPs traffic leaving the node ) } f4 := iptV4.(*util.FakeIPTables) diff --git a/go-controller/pkg/node/gateway_iptables.go b/go-controller/pkg/node/gateway_iptables.go index 51d033de1e..d0ea1afe80 100644 --- a/go-controller/pkg/node/gateway_iptables.go +++ b/go-controller/pkg/node/gateway_iptables.go @@ -427,15 +427,18 @@ func getUDNMasqueradeRules(protocol iptables.Protocol) []nodeipt.Rule { // NOTE: Ordering is important here, the RETURN must come before // the MASQUERADE rule. Please don't change the ordering. srcUDNMasqueradePrefix := config.Gateway.V4MasqueradeSubnet - // defaultNetworkReservedMasqueradePrefix contains the first 6IPs in the masquerade - // range that shouldn't be MASQUERADED. Hence /29 and /125 is intentionally hardcoded here - defaultNetworkReservedMasqueradePrefix := config.Gateway.MasqueradeIPs.V4HostMasqueradeIP.String() + "/29" ipFamily := utilnet.IPv4 if protocol == iptables.ProtocolIPv6 { srcUDNMasqueradePrefix = config.Gateway.V6MasqueradeSubnet - defaultNetworkReservedMasqueradePrefix = config.Gateway.MasqueradeIPs.V6HostMasqueradeIP.String() + "/125" ipFamily = utilnet.IPv6 } + // defaultNetworkReservedMasqueradePrefix contains the first 6 IPs in the + // masquerade range that shouldn't be masqueraded. Hence it's always 3 bits (8 + // IPs) wide, regardless of IP family. + _, ipnet, _ := net.ParseCIDR(srcUDNMasqueradePrefix) + _, len := ipnet.Mask.Size() + defaultNetworkReservedMasqueradePrefix := fmt.Sprintf("%s/%d", ipnet.IP.String(), len-3) + rules := []nodeipt.Rule{ { Table: "nat", diff --git a/go-controller/pkg/node/gateway_localnet_linux_test.go b/go-controller/pkg/node/gateway_localnet_linux_test.go index 2c4583b716..224c7779a1 100644 --- a/go-controller/pkg/node/gateway_localnet_linux_test.go +++ b/go-controller/pkg/node/gateway_localnet_linux_test.go @@ -1116,6 +1116,7 @@ var _ = Describe("Node Operations", func() { expectedNFT := getBaseNFTRules(fakeMgmtPortConfig.ifName) err = nodenft.MatchNFTRules(expectedNFT, nft.Dump()) + Expect(err).NotTo(HaveOccurred()) flows := fNPW.ofm.getFlowsByKey("NodePort_namespace1_service1_tcp_31111") Expect(flows).To(BeNil()) @@ -1342,6 +1343,7 @@ var _ = Describe("Node Operations", func() { expectedNFT := getBaseNFTRules(fakeMgmtPortConfig.ifName) err = nodenft.MatchNFTRules(expectedNFT, nft.Dump()) + Expect(err).NotTo(HaveOccurred()) return nil } diff --git a/go-controller/pkg/node/udn_isolation.go b/go-controller/pkg/node/udn_isolation.go index ab0a2d1c31..14363de34a 100644 --- a/go-controller/pkg/node/udn_isolation.go +++ b/go-controller/pkg/node/udn_isolation.go @@ -122,7 +122,7 @@ func (m *UDNHostIsolationManager) Start(ctx context.Context) error { // As a side effect, all kubelet probes will fail, but host isolation will still work. message := fmt.Sprintf("Kubelet probes for UDN are not supported on the node %s as it uses cgroup v1.", m.nodeName) klog.Warning(message) - nodeRef := &kapi.ObjectReference{ + nodeRef := &v1.ObjectReference{ Kind: "Node", Name: m.nodeName, } @@ -517,6 +517,10 @@ func (m *UDNHostIsolationManager) getPodInfo(podKey string, pod *v1.Pod) (*podIn // only add pods with primary UDN primaryUDN, err := m.isPodPrimaryUDN(pod) if err != nil { + if util.IsAnnotationNotSetError(err) { + // pod IPs were not assigned yet, expecting an update event + return nil, nil, nil + } return nil, nil, fmt.Errorf("failed to check if pod %s is in primary UDN: %w", podKey, err) } if !primaryUDN { diff --git a/go-controller/pkg/node/udn_isolation_test.go b/go-controller/pkg/node/udn_isolation_test.go index 8b55bcd237..58ae4cbceb 100644 --- a/go-controller/pkg/node/udn_isolation_test.go +++ b/go-controller/pkg/node/udn_isolation_test.go @@ -3,11 +3,12 @@ package node import ( "context" "fmt" + "net" + "strings" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - "net" "sigs.k8s.io/yaml" - "strings" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -349,6 +350,23 @@ add rule inet ovn-kubernetes udn-isolation ip6 daddr @udn-pod-default-ips-v6 dro Expect(nft.Dump()).To(Equal(getExpectedDump(nil, nil))) }) + It("correctly handles not ready pods", func() { + notReadyPod := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "notready", + UID: ktypes.UID("notready"), + Namespace: defaultNamespace, + }, + } + fakeClient = util.GetOVNClientset(notReadyPod).GetNodeClientset() + var err error + wf, err = factory.NewNodeWatchFactory(fakeClient, "node1") + Expect(err).NotTo(HaveOccurred()) + manager = NewUDNHostIsolationManager(true, true, wf.PodCoreInformer(), "node1", nil) + Expect(wf.Start()).To(Succeed()) + Expect(manager.reconcilePod(notReadyPod.Namespace + "/" + notReadyPod.Name)).To(Succeed()) + }) + Context("updates pod IPs", func() { It("on restart", func() { start( diff --git a/go-controller/pkg/ovn/egressip_test.go b/go-controller/pkg/ovn/egressip_test.go index f6657abaff..c4a57346d9 100644 --- a/go-controller/pkg/ovn/egressip_test.go +++ b/go-controller/pkg/ovn/egressip_test.go @@ -277,6 +277,15 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" UUID: node1.Name + "-UUID", Name: node1.Name, } + dynamicNeighRouters := "true" + if config.OVNKubernetesFeature.EnableInterconnect { + dynamicNeighRouters = "false" + } + + logicalRouterOptions := map[string]string{ + "dynamic_neigh_routers": dynamicNeighRouters, + } + fakeOvn.startWithDBSetup( libovsdbtest.TestSetup{ NBData: []libovsdbtest.TestData{ @@ -290,9 +299,10 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" UUID: types.OVNClusterRouter + "-UUID", }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1.Name, - UUID: types.GWRouterPrefix + node1.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Name: types.GWRouterPrefix + node1.Name, + UUID: types.GWRouterPrefix + node1.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: types.EXTSwitchToGWRouterPrefix + types.GWRouterPrefix + node1Name + "-UUID", @@ -392,10 +402,11 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" }, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1.Name, - UUID: types.GWRouterPrefix + node1.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, - Nat: []string{"egressip-nat-UUID"}, + Name: types.GWRouterPrefix + node1.Name, + UUID: types.GWRouterPrefix + node1.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Nat: []string{"egressip-nat-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ Name: types.OVNClusterRouter, @@ -477,6 +488,14 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" Name: node1.Name, Ports: []string{"k8s-" + node1.Name + "-UUID"}, } + dynamicNeighRouters := "true" + if config.OVNKubernetesFeature.EnableInterconnect { + dynamicNeighRouters = "false" + } + + logicalRouterOptions := map[string]string{ + "dynamic_neigh_routers": dynamicNeighRouters, + } fakeOvn.startWithDBSetup( libovsdbtest.TestSetup{ NBData: []libovsdbtest.TestData{ @@ -490,9 +509,10 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" UUID: types.OVNClusterRouter + "-UUID", }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1.Name, - UUID: types.GWRouterPrefix + node1.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Name: types.GWRouterPrefix + node1.Name, + UUID: types.GWRouterPrefix + node1.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: types.EXTSwitchToGWRouterPrefix + types.GWRouterPrefix + node1Name + "-UUID", @@ -587,9 +607,10 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" ExternalIDs: getEgressIPLRPNoReRoutePodToNodeDbIDs(IPFamilyValueV4, types.DefaultNetworkName, fakeOvn.controller.eIPC.controllerName).GetExternalIDs(), }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1.Name, - UUID: types.GWRouterPrefix + node1.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Name: types.GWRouterPrefix + node1.Name, + UUID: types.GWRouterPrefix + node1.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ Name: types.OVNClusterRouter, @@ -690,6 +711,14 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" UUID: node2.Name + "-UUID", Name: node2.Name, } + dynamicNeighRouters := "true" + if config.OVNKubernetesFeature.EnableInterconnect { + dynamicNeighRouters = "false" + } + + logicalRouterOptions := map[string]string{ + "dynamic_neigh_routers": dynamicNeighRouters, + } fakeOvn.startWithDBSetup( libovsdbtest.TestSetup{ NBData: []libovsdbtest.TestData{ @@ -708,14 +737,16 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" UUID: types.OVNClusterRouter + "-UUID", }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1.Name, - UUID: types.GWRouterPrefix + node1.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Name: types.GWRouterPrefix + node1.Name, + UUID: types.GWRouterPrefix + node1.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2.Name, - UUID: types.GWRouterPrefix + node2.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, + Name: types.GWRouterPrefix + node2.Name, + UUID: types.GWRouterPrefix + node2.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: types.EXTSwitchToGWRouterPrefix + types.GWRouterPrefix + node1Name + "-UUID", @@ -853,15 +884,17 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" }, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1.Name, - UUID: types.GWRouterPrefix + node1.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Name: types.GWRouterPrefix + node1.Name, + UUID: types.GWRouterPrefix + node1.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2.Name, - UUID: types.GWRouterPrefix + node2.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, - Nat: []string{"egressip-nat-UUID"}, + Name: types.GWRouterPrefix + node2.Name, + UUID: types.GWRouterPrefix + node2.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, + Nat: []string{"egressip-nat-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ Name: types.OVNClusterRouter, @@ -990,6 +1023,14 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" UUID: node3.Name + "-UUID", Name: node3.Name, } + dynamicNeighRouters := "true" + if config.OVNKubernetesFeature.EnableInterconnect { + dynamicNeighRouters = "false" + } + + logicalRouterOptions := map[string]string{ + "dynamic_neigh_routers": dynamicNeighRouters, + } initialDB := libovsdbtest.TestSetup{ NBData: []libovsdbtest.TestData{ &nbdb.LogicalRouterPort{ @@ -1012,19 +1053,22 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" UUID: types.OVNClusterRouter + "-UUID", }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1.Name, - UUID: types.GWRouterPrefix + node1.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Name: types.GWRouterPrefix + node1.Name, + UUID: types.GWRouterPrefix + node1.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2.Name, - UUID: types.GWRouterPrefix + node2.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, + Name: types.GWRouterPrefix + node2.Name, + UUID: types.GWRouterPrefix + node2.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node3.Name, - UUID: types.GWRouterPrefix + node3.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node3.Name + "-UUID"}, + Name: types.GWRouterPrefix + node3.Name, + UUID: types.GWRouterPrefix + node3.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node3.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: types.EXTSwitchToGWRouterPrefix + types.GWRouterPrefix + node1Name + "-UUID", @@ -1213,20 +1257,23 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" }, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1.Name, - UUID: types.GWRouterPrefix + node1.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Name: types.GWRouterPrefix + node1.Name, + UUID: types.GWRouterPrefix + node1.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2.Name, - UUID: types.GWRouterPrefix + node2.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, - Nat: []string{"egressip-nat-UUID"}, + Name: types.GWRouterPrefix + node2.Name, + UUID: types.GWRouterPrefix + node2.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, + Nat: []string{"egressip-nat-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node3.Name, - UUID: types.GWRouterPrefix + node3.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node3.Name + "-UUID"}, + Name: types.GWRouterPrefix + node3.Name, + UUID: types.GWRouterPrefix + node3.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node3.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ Name: types.OVNClusterRouter, @@ -1384,6 +1431,14 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" Name: node3.Name, Ports: []string{"k8s-" + node3.Name + "-UUID"}, } + dynamicNeighRouters := "true" + if config.OVNKubernetesFeature.EnableInterconnect { + dynamicNeighRouters = "false" + } + + logicalRouterOptions := map[string]string{ + "dynamic_neigh_routers": dynamicNeighRouters, + } initialDB := libovsdbtest.TestSetup{ NBData: []libovsdbtest.TestData{ &nbdb.LogicalRouterPort{ @@ -1406,19 +1461,22 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" UUID: types.OVNClusterRouter + "-UUID", }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1.Name, - UUID: types.GWRouterPrefix + node1.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Name: types.GWRouterPrefix + node1.Name, + UUID: types.GWRouterPrefix + node1.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2.Name, - UUID: types.GWRouterPrefix + node2.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, + Name: types.GWRouterPrefix + node2.Name, + UUID: types.GWRouterPrefix + node2.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node3.Name, - UUID: types.GWRouterPrefix + node3.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node3.Name + "-UUID"}, + Name: types.GWRouterPrefix + node3.Name, + UUID: types.GWRouterPrefix + node3.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node3.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: types.EXTSwitchToGWRouterPrefix + types.GWRouterPrefix + node1Name + "-UUID", @@ -1612,20 +1670,23 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" ExternalIDs: getEgressIPLRPNoReRoutePodToNodeDbIDs(IPFamilyValueV4, types.DefaultNetworkName, fakeOvn.controller.eIPC.controllerName).GetExternalIDs(), }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1.Name, - UUID: types.GWRouterPrefix + node1.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Name: types.GWRouterPrefix + node1.Name, + UUID: types.GWRouterPrefix + node1.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2.Name, - UUID: types.GWRouterPrefix + node2.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, - Nat: []string{}, + Name: types.GWRouterPrefix + node2.Name, + UUID: types.GWRouterPrefix + node2.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, + Nat: []string{}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node3.Name, - UUID: types.GWRouterPrefix + node3.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node3.Name + "-UUID"}, + Name: types.GWRouterPrefix + node3.Name, + UUID: types.GWRouterPrefix + node3.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node3.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ Name: types.OVNClusterRouter, @@ -1792,6 +1853,14 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" Name: node2.Name, Ports: []string{"k8s-" + node2.Name + "-UUID"}, } + dynamicNeighRouters := "true" + if config.OVNKubernetesFeature.EnableInterconnect { + dynamicNeighRouters = "false" + } + + logicalRouterOptions := map[string]string{ + "dynamic_neigh_routers": dynamicNeighRouters, + } fakeOvn.startWithDBSetup( libovsdbtest.TestSetup{ @@ -1811,15 +1880,17 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" UUID: types.OVNClusterRouter + "-UUID", }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1.Name, - UUID: types.GWRouterPrefix + node1.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Name: types.GWRouterPrefix + node1.Name, + UUID: types.GWRouterPrefix + node1.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2.Name, - UUID: types.GWRouterPrefix + node2.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, - Nat: nil, + Name: types.GWRouterPrefix + node2.Name, + UUID: types.GWRouterPrefix + node2.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, + Nat: nil, + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: types.EXTSwitchToGWRouterPrefix + types.GWRouterPrefix + node1Name + "-UUID", @@ -1956,14 +2027,16 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" ExternalIDs: getEgressIPLRPNoReRoutePodToNodeDbIDs(IPFamilyValueV4, types.DefaultNetworkName, fakeOvn.controller.eIPC.controllerName).GetExternalIDs(), }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1.Name, - UUID: types.GWRouterPrefix + node1.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Name: types.GWRouterPrefix + node1.Name, + UUID: types.GWRouterPrefix + node1.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2.Name, - UUID: types.GWRouterPrefix + node2.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, + Name: types.GWRouterPrefix + node2.Name, + UUID: types.GWRouterPrefix + node2.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ Name: types.OVNClusterRouter, @@ -2158,7 +2231,14 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" Name: node2.Name, Ports: []string{"k8s-" + node2.Name + "-UUID"}, } + dynamicNeighRouters := "true" + if config.OVNKubernetesFeature.EnableInterconnect { + dynamicNeighRouters = "false" + } + logicalRouterOptions := map[string]string{ + "dynamic_neigh_routers": dynamicNeighRouters, + } fakeOvn.startWithDBSetup( libovsdbtest.TestSetup{ NBData: []libovsdbtest.TestData{ @@ -2177,15 +2257,17 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" UUID: types.OVNClusterRouter + "-UUID", }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1.Name, - UUID: types.GWRouterPrefix + node1.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Name: types.GWRouterPrefix + node1.Name, + UUID: types.GWRouterPrefix + node1.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2.Name, - UUID: types.GWRouterPrefix + node2.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, - Nat: nil, + Name: types.GWRouterPrefix + node2.Name, + UUID: types.GWRouterPrefix + node2.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, + Nat: nil, + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: types.EXTSwitchToGWRouterPrefix + types.GWRouterPrefix + node1Name + "-UUID", @@ -2390,15 +2472,17 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" ExternalIDs: getEgressIPLRPNoReRoutePodToNodeDbIDs(IPFamilyValueV4, types.DefaultNetworkName, fakeOvn.controller.eIPC.controllerName).GetExternalIDs(), }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1.Name, - UUID: types.GWRouterPrefix + node1.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, - Nat: []string{}, + Name: types.GWRouterPrefix + node1.Name, + UUID: types.GWRouterPrefix + node1.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Nat: []string{}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2.Name, - UUID: types.GWRouterPrefix + node2.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, + Name: types.GWRouterPrefix + node2.Name, + UUID: types.GWRouterPrefix + node2.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ Name: types.OVNClusterRouter, @@ -2591,6 +2675,15 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" Name: node2.Name, Ports: []string{"k8s-" + node2.Name + "-UUID"}, } + dynamicNeighRouters := "true" + if config.OVNKubernetesFeature.EnableInterconnect { + dynamicNeighRouters = "false" + } + + logicalRouterOptions := map[string]string{ + "dynamic_neigh_routers": dynamicNeighRouters, + } + fakeOvn.startWithDBSetup( libovsdbtest.TestSetup{ NBData: []libovsdbtest.TestData{ @@ -2609,9 +2702,10 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" UUID: types.OVNClusterRouter + "-UUID", }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1.Name, - UUID: types.GWRouterPrefix + node1.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Name: types.GWRouterPrefix + node1.Name, + UUID: types.GWRouterPrefix + node1.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalSwitch{ UUID: types.ExternalSwitchPrefix + node1.Name + "-UUID", @@ -2619,9 +2713,10 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" Ports: []string{types.EXTSwitchToGWRouterPrefix + types.GWRouterPrefix + node1Name + "-UUID"}, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2.Name, - UUID: types.GWRouterPrefix + node2.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, + Name: types.GWRouterPrefix + node2.Name, + UUID: types.GWRouterPrefix + node2.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalSwitch{ UUID: types.ExternalSwitchPrefix + node2.Name + "-UUID", @@ -2746,16 +2841,18 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" ExternalIDs: getEgressIPLRPNoReRoutePodToJoinDbIDs(IPFamilyValueV4, types.DefaultNetworkName, fakeOvn.controller.eIPC.controllerName).GetExternalIDs(), }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1.Name, - UUID: types.GWRouterPrefix + node1.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, - Nat: []string{"egressip-nat1-UUID"}, + Name: types.GWRouterPrefix + node1.Name, + UUID: types.GWRouterPrefix + node1.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Nat: []string{"egressip-nat1-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2.Name, - UUID: types.GWRouterPrefix + node2.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, - Nat: []string{}, + Name: types.GWRouterPrefix + node2.Name, + UUID: types.GWRouterPrefix + node2.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, + Nat: []string{}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ Name: types.OVNClusterRouter, @@ -2898,9 +2995,10 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" ExternalIDs: getEgressIPLRPNoReRoutePodToJoinDbIDs(IPFamilyValueV4, types.DefaultNetworkName, fakeOvn.controller.eIPC.controllerName).GetExternalIDs(), }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2.Name, - UUID: types.GWRouterPrefix + node2.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, + Name: types.GWRouterPrefix + node2.Name, + UUID: types.GWRouterPrefix + node2.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ Name: types.OVNClusterRouter, @@ -3035,7 +3133,14 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" Name: node2.Name, Ports: []string{"k8s-" + node2.Name + "-UUID"}, } + dynamicNeighRouters := "true" + if config.OVNKubernetesFeature.EnableInterconnect { + dynamicNeighRouters = "false" + } + logicalRouterOptions := map[string]string{ + "dynamic_neigh_routers": dynamicNeighRouters, + } fakeOvn.startWithDBSetup( libovsdbtest.TestSetup{ NBData: []libovsdbtest.TestData{ @@ -3054,15 +3159,17 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" UUID: types.OVNClusterRouter + "-UUID", }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1.Name, - UUID: types.GWRouterPrefix + node1.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Name: types.GWRouterPrefix + node1.Name, + UUID: types.GWRouterPrefix + node1.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2.Name, - UUID: types.GWRouterPrefix + node2.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, - Nat: nil, + Name: types.GWRouterPrefix + node2.Name, + UUID: types.GWRouterPrefix + node2.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, + Nat: nil, + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: types.EXTSwitchToGWRouterPrefix + types.GWRouterPrefix + node1Name + "-UUID", @@ -3202,14 +3309,16 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" ExternalIDs: getEgressIPLRPNoReRoutePodToJoinDbIDs(IPFamilyValueV4, types.DefaultNetworkName, fakeOvn.controller.eIPC.controllerName).GetExternalIDs(), }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1.Name, - UUID: types.GWRouterPrefix + node1.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Name: types.GWRouterPrefix + node1.Name, + UUID: types.GWRouterPrefix + node1.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2.Name, - UUID: types.GWRouterPrefix + node2.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, + Name: types.GWRouterPrefix + node2.Name, + UUID: types.GWRouterPrefix + node2.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ Name: types.OVNClusterRouter, @@ -3360,7 +3469,14 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" annotations["k8s.ovn.org/remote-zone-migrated"] = "remote" // used only for ic=true test } node2 := getNodeObj(node2Name, annotations, map[string]string{}) // add node to avoid errori-ing out on transit switch IP fetch + dynamicNeighRouters := "true" + if config.OVNKubernetesFeature.EnableInterconnect { + dynamicNeighRouters = "false" + } + logicalRouterOptions := map[string]string{ + "dynamic_neigh_routers": dynamicNeighRouters, + } fakeOvn.startWithDBSetup( libovsdbtest.TestSetup{ NBData: []libovsdbtest.TestData{ @@ -3379,15 +3495,17 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" UUID: types.OVNClusterRouter + "-UUID", }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1Name, - UUID: types.GWRouterPrefix + node1Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1Name + "-UUID"}, + Name: types.GWRouterPrefix + node1Name, + UUID: types.GWRouterPrefix + node1Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2Name, - UUID: types.GWRouterPrefix + node2Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, - Nat: nil, + Name: types.GWRouterPrefix + node2Name, + UUID: types.GWRouterPrefix + node2Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, + Nat: nil, + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: "k8s-" + node1.Name + "-UUID", @@ -3489,15 +3607,17 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" Networks: []string{node2LogicalRouterIfAddrV6, node2LogicalRouterIfAddrV6}, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1Name, - UUID: types.GWRouterPrefix + node1Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1Name + "-UUID"}, + Name: types.GWRouterPrefix + node1Name, + UUID: types.GWRouterPrefix + node1Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2Name, - UUID: types.GWRouterPrefix + node2Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, - Nat: []string{"egressip-nat-UUID"}, + Name: types.GWRouterPrefix + node2Name, + UUID: types.GWRouterPrefix + node2Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, + Nat: []string{"egressip-nat-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: "k8s-" + node1.Name + "-UUID", @@ -3564,15 +3684,17 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" Networks: []string{node2LogicalRouterIfAddrV6, node2LogicalRouterIfAddrV6}, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1Name, - UUID: types.GWRouterPrefix + node1Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1Name + "-UUID"}, + Name: types.GWRouterPrefix + node1Name, + UUID: types.GWRouterPrefix + node1Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2Name, - UUID: types.GWRouterPrefix + node2Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, - Nat: nil, + Name: types.GWRouterPrefix + node2Name, + UUID: types.GWRouterPrefix + node2Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, + Nat: nil, + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: "k8s-" + node1.Name + "-UUID", @@ -3628,7 +3750,14 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" _, node1Subnet, _ := net.ParseCIDR(v6Node1Subnet) node2 := nodes[1] _, node2Subnet, _ := net.ParseCIDR(v6Node2Subnet) + dynamicNeighRouters := "true" + if config.OVNKubernetesFeature.EnableInterconnect { + dynamicNeighRouters = "false" + } + logicalRouterOptions := map[string]string{ + "dynamic_neigh_routers": dynamicNeighRouters, + } fakeOvn.startWithDBSetup( libovsdbtest.TestSetup{ NBData: []libovsdbtest.TestData{ @@ -3647,15 +3776,17 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" UUID: types.OVNClusterRouter + "-UUID", }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1Name, - UUID: types.GWRouterPrefix + node1Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1Name + "-UUID"}, + Name: types.GWRouterPrefix + node1Name, + UUID: types.GWRouterPrefix + node1Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2Name, - UUID: types.GWRouterPrefix + node2Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, - Nat: nil, + Name: types.GWRouterPrefix + node2Name, + UUID: types.GWRouterPrefix + node2Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, + Nat: nil, + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: "k8s-" + node1.Name + "-UUID", @@ -3749,15 +3880,17 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" Networks: []string{node2LogicalRouterIfAddrV6}, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1Name, - UUID: types.GWRouterPrefix + node1Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1Name + "-UUID"}, + Name: types.GWRouterPrefix + node1Name, + UUID: types.GWRouterPrefix + node1Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2Name, - UUID: types.GWRouterPrefix + node2Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, - Nat: []string{"egressip-nat-UUID"}, + Name: types.GWRouterPrefix + node2Name, + UUID: types.GWRouterPrefix + node2Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, + Nat: []string{"egressip-nat-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: "k8s-" + node1.Name + "-UUID", @@ -3846,7 +3979,14 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" egressNamespace := newNamespace(eipNamespace) _, node1Subnet, _ := net.ParseCIDR(v6Node1Subnet) _, node2Subnet, _ := net.ParseCIDR(v6Node2Subnet) + dynamicNeighRouters := "true" + if config.OVNKubernetesFeature.EnableInterconnect { + dynamicNeighRouters = "false" + } + logicalRouterOptions := map[string]string{ + "dynamic_neigh_routers": dynamicNeighRouters, + } fakeOvn.startWithDBSetup( libovsdbtest.TestSetup{ NBData: []libovsdbtest.TestData{ @@ -3860,13 +4000,15 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" UUID: types.OVNClusterRouter + "-UUID", }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1Name, - UUID: types.GWRouterPrefix + node1Name + "-UUID", + Name: types.GWRouterPrefix + node1Name, + UUID: types.GWRouterPrefix + node1Name + "-UUID", + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2Name, - UUID: types.GWRouterPrefix + node2Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, + Name: types.GWRouterPrefix + node2Name, + UUID: types.GWRouterPrefix + node2Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: "k8s-" + node1Name + "-UUID", @@ -3969,14 +4111,16 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" }, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1Name, - UUID: types.GWRouterPrefix + node1Name + "-UUID", + Name: types.GWRouterPrefix + node1Name, + UUID: types.GWRouterPrefix + node1Name + "-UUID", + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2Name, - UUID: types.GWRouterPrefix + node2Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, - Nat: []string{"egressip-nat-UUID"}, + Name: types.GWRouterPrefix + node2Name, + UUID: types.GWRouterPrefix + node2Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, + Nat: []string{"egressip-nat-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: "k8s-" + node1Name + "-UUID", @@ -4205,6 +4349,14 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" egressNamespace := newNamespace(eipNamespace) _, node1Subnet, _ := net.ParseCIDR(v6Node1Subnet) _, node2Subnet, _ := net.ParseCIDR(v6Node2Subnet) + dynamicNeighRouters := "true" + if config.OVNKubernetesFeature.EnableInterconnect { + dynamicNeighRouters = "false" + } + + logicalRouterOptions := map[string]string{ + "dynamic_neigh_routers": dynamicNeighRouters, + } fakeOvn.startWithDBSetup( libovsdbtest.TestSetup{ NBData: []libovsdbtest.TestData{ @@ -4218,14 +4370,16 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" UUID: types.OVNClusterRouter + "-UUID", }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1Name, - UUID: types.GWRouterPrefix + node1Name + "-UUID", + Name: types.GWRouterPrefix + node1Name, + UUID: types.GWRouterPrefix + node1Name + "-UUID", + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2Name, - UUID: types.GWRouterPrefix + node2Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, - Nat: nil, + Name: types.GWRouterPrefix + node2Name, + UUID: types.GWRouterPrefix + node2Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, + Nat: nil, + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: "k8s-" + node1Name + "-UUID", @@ -4328,14 +4482,16 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" Networks: []string{node2LogicalRouterIfAddrV6}, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1Name, - UUID: types.GWRouterPrefix + node1Name + "-UUID", + Name: types.GWRouterPrefix + node1Name, + UUID: types.GWRouterPrefix + node1Name + "-UUID", + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2Name, - UUID: types.GWRouterPrefix + node2Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, - Nat: []string{"egressip-nat-UUID"}, + Name: types.GWRouterPrefix + node2Name, + UUID: types.GWRouterPrefix + node2Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, + Nat: []string{"egressip-nat-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: "k8s-" + node1Name + "-UUID", @@ -4456,6 +4612,14 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" } _, node1Subnet, _ := net.ParseCIDR(v6Node1Subnet) _, node2Subnet, _ := net.ParseCIDR(v6Node2Subnet) + dynamicNeighRouters := "true" + if config.OVNKubernetesFeature.EnableInterconnect { + dynamicNeighRouters = "false" + } + + logicalRouterOptions := map[string]string{ + "dynamic_neigh_routers": dynamicNeighRouters, + } fakeOvn.startWithDBSetup( libovsdbtest.TestSetup{ NBData: []libovsdbtest.TestData{ @@ -4469,14 +4633,16 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" UUID: types.OVNClusterRouter + "-UUID", }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1Name, - UUID: types.GWRouterPrefix + node1Name + "-UUID", + Name: types.GWRouterPrefix + node1Name, + UUID: types.GWRouterPrefix + node1Name + "-UUID", + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2Name, - UUID: types.GWRouterPrefix + node2Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, - Nat: nil, + Name: types.GWRouterPrefix + node2Name, + UUID: types.GWRouterPrefix + node2Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, + Nat: nil, + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: "k8s-" + node1Name + "-UUID", @@ -4565,14 +4731,16 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" Networks: []string{node2LogicalRouterIfAddrV6}, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1Name, - UUID: types.GWRouterPrefix + node1Name + "-UUID", + Name: types.GWRouterPrefix + node1Name, + UUID: types.GWRouterPrefix + node1Name + "-UUID", + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2Name, - UUID: types.GWRouterPrefix + node2Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, - Nat: []string{"egressip-nat-UUID"}, + Name: types.GWRouterPrefix + node2Name, + UUID: types.GWRouterPrefix + node2Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, + Nat: []string{"egressip-nat-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: "k8s-" + node1Name + "-UUID", @@ -4621,14 +4789,16 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" Networks: []string{node2LogicalRouterIfAddrV6}, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1Name, - UUID: types.GWRouterPrefix + node1Name + "-UUID", + Name: types.GWRouterPrefix + node1Name, + UUID: types.GWRouterPrefix + node1Name + "-UUID", + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2Name, - UUID: types.GWRouterPrefix + node2Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, - Nat: nil, + Name: types.GWRouterPrefix + node2Name, + UUID: types.GWRouterPrefix + node2Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, + Nat: nil, + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: "k8s-" + node1Name + "-UUID", @@ -4680,6 +4850,14 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" } _, node1Subnet, _ := net.ParseCIDR(v6Node1Subnet) _, node2Subnet, _ := net.ParseCIDR(v6Node2Subnet) + dynamicNeighRouters := "true" + if config.OVNKubernetesFeature.EnableInterconnect { + dynamicNeighRouters = "false" + } + + logicalRouterOptions := map[string]string{ + "dynamic_neigh_routers": dynamicNeighRouters, + } fakeOvn.startWithDBSetup( libovsdbtest.TestSetup{ NBData: []libovsdbtest.TestData{ @@ -4693,14 +4871,16 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" UUID: types.OVNClusterRouter + "-UUID", }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1Name, - UUID: types.GWRouterPrefix + node1Name + "-UUID", + Name: types.GWRouterPrefix + node1Name, + UUID: types.GWRouterPrefix + node1Name + "-UUID", + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2Name, - UUID: types.GWRouterPrefix + node2Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, - Nat: nil, + Name: types.GWRouterPrefix + node2Name, + UUID: types.GWRouterPrefix + node2Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, + Nat: nil, + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: "k8s-" + node1Name + "-UUID", @@ -4810,14 +4990,16 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" Networks: []string{nodeLogicalRouterIfAddrV6}, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1Name, - UUID: types.GWRouterPrefix + node1Name + "-UUID", + Name: types.GWRouterPrefix + node1Name, + UUID: types.GWRouterPrefix + node1Name + "-UUID", + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2Name, - UUID: types.GWRouterPrefix + node2Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, - Nat: []string{"egressip-nat-UUID"}, + Name: types.GWRouterPrefix + node2Name, + UUID: types.GWRouterPrefix + node2Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, + Nat: []string{"egressip-nat-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: "k8s-" + node1Name + "-UUID", @@ -4864,14 +5046,16 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" Networks: []string{nodeLogicalRouterIfAddrV6}, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1Name, - UUID: types.GWRouterPrefix + node1Name + "-UUID", + Name: types.GWRouterPrefix + node1Name, + UUID: types.GWRouterPrefix + node1Name + "-UUID", + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2Name, - UUID: types.GWRouterPrefix + node2Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, - Nat: nil, + Name: types.GWRouterPrefix + node2Name, + UUID: types.GWRouterPrefix + node2Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, + Nat: nil, + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: "k8s-" + node1Name + "-UUID", @@ -4924,6 +5108,14 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" _, node1Subnet, _ := net.ParseCIDR(v6Node1Subnet) _, node2Subnet, _ := net.ParseCIDR(v6Node2Subnet) egressIPServedPodsASv4, _ := buildEgressIPServedPodsAddressSets(nil, types.DefaultNetworkName, DefaultNetworkControllerName) + dynamicNeighRouters := "true" + if config.OVNKubernetesFeature.EnableInterconnect { + dynamicNeighRouters = "false" + } + + logicalRouterOptions := map[string]string{ + "dynamic_neigh_routers": dynamicNeighRouters, + } fakeOvn.startWithDBSetup( libovsdbtest.TestSetup{ NBData: []libovsdbtest.TestData{ @@ -4937,14 +5129,16 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" UUID: types.OVNClusterRouter + "-UUID", }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1Name, - UUID: types.GWRouterPrefix + node1Name + "-UUID", + Name: types.GWRouterPrefix + node1Name, + UUID: types.GWRouterPrefix + node1Name + "-UUID", + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2Name, - UUID: types.GWRouterPrefix + node2Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, - Nat: nil, + Name: types.GWRouterPrefix + node2Name, + UUID: types.GWRouterPrefix + node2Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, + Nat: nil, + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: "k8s-" + node1Name + "-UUID", @@ -5044,14 +5238,16 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" }, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1Name, - UUID: types.GWRouterPrefix + node1Name + "-UUID", + Name: types.GWRouterPrefix + node1Name, + UUID: types.GWRouterPrefix + node1Name + "-UUID", + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2Name, - UUID: types.GWRouterPrefix + node2Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, - Nat: []string{"egressip-nat-UUID"}, + Name: types.GWRouterPrefix + node2Name, + UUID: types.GWRouterPrefix + node2Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, + Nat: []string{"egressip-nat-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: "k8s-" + node1Name + "-UUID", @@ -5103,14 +5299,16 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" Networks: []string{node2LogicalRouterIfAddrV6}, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1Name, - UUID: types.GWRouterPrefix + node1Name + "-UUID", + Name: types.GWRouterPrefix + node1Name, + UUID: types.GWRouterPrefix + node1Name + "-UUID", + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2Name, - UUID: types.GWRouterPrefix + node2Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, - Nat: nil, + Name: types.GWRouterPrefix + node2Name, + UUID: types.GWRouterPrefix + node2Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, + Nat: nil, + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: "k8s-" + node1Name + "-UUID", @@ -5280,6 +5478,14 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" Name: node2Name, Ports: []string{"k8s-" + node2Name + "-UUID"}, } + dynamicNeighRouters := "true" + if config.OVNKubernetesFeature.EnableInterconnect { + dynamicNeighRouters = "false" + } + + logicalRouterOptions := map[string]string{ + "dynamic_neigh_routers": dynamicNeighRouters, + } fakeOvn.startWithDBSetup( libovsdbtest.TestSetup{ NBData: []libovsdbtest.TestData{ @@ -5298,14 +5504,16 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" UUID: types.OVNClusterRouter + "-UUID", }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1.Name, - UUID: types.GWRouterPrefix + node1.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Name: types.GWRouterPrefix + node1.Name, + UUID: types.GWRouterPrefix + node1.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2.Name, - UUID: types.GWRouterPrefix + node2.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, + Name: types.GWRouterPrefix + node2.Name, + UUID: types.GWRouterPrefix + node2.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: types.EXTSwitchToGWRouterPrefix + types.GWRouterPrefix + node1Name + "-UUID", @@ -5452,14 +5660,16 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" ExternalIDs: getEgressIPLRPNoReRoutePodToJoinDbIDs(IPFamilyValueV4, types.DefaultNetworkName, fakeOvn.controller.eIPC.controllerName).GetExternalIDs(), }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + assignmentNode1, - UUID: types.GWRouterPrefix + assignmentNode1 + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Name: types.GWRouterPrefix + assignmentNode1, + UUID: types.GWRouterPrefix + assignmentNode1 + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + assignmentNode2, - UUID: types.GWRouterPrefix + assignmentNode2 + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, + Name: types.GWRouterPrefix + assignmentNode2, + UUID: types.GWRouterPrefix + assignmentNode2 + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ Name: types.OVNClusterRouter, @@ -5615,14 +5825,16 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" ExternalIDs: getEgressIPLRPNoReRoutePodToJoinDbIDs(IPFamilyValueV4, types.DefaultNetworkName, fakeOvn.controller.eIPC.controllerName).GetExternalIDs(), }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + assignmentNode1, - UUID: types.GWRouterPrefix + assignmentNode1 + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Name: types.GWRouterPrefix + assignmentNode1, + UUID: types.GWRouterPrefix + assignmentNode1 + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + assignmentNode2, - UUID: types.GWRouterPrefix + assignmentNode2 + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, + Name: types.GWRouterPrefix + assignmentNode2, + UUID: types.GWRouterPrefix + assignmentNode2 + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ Name: types.OVNClusterRouter, @@ -5755,7 +5967,14 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" _, node1Subnet, _ := net.ParseCIDR(v6Node1Subnet) _, node2Subnet, _ := net.ParseCIDR(v6Node2Subnet) egressIPServedPodsASv4, _ := buildEgressIPServedPodsAddressSets(nil, types.DefaultNetworkName, DefaultNetworkControllerName) + dynamicNeighRouters := "true" + if config.OVNKubernetesFeature.EnableInterconnect { + dynamicNeighRouters = "false" + } + logicalRouterOptions := map[string]string{ + "dynamic_neigh_routers": dynamicNeighRouters, + } fakeOvn.startWithDBSetup( libovsdbtest.TestSetup{ NBData: []libovsdbtest.TestData{ @@ -5769,14 +5988,16 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" UUID: types.OVNClusterRouter + "-UUID", }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1Name, - UUID: types.GWRouterPrefix + node1Name + "-UUID", + Name: types.GWRouterPrefix + node1Name, + UUID: types.GWRouterPrefix + node1Name + "-UUID", + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2Name, - UUID: types.GWRouterPrefix + node2Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, - Nat: nil, + Name: types.GWRouterPrefix + node2Name, + UUID: types.GWRouterPrefix + node2Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, + Nat: nil, + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: "k8s-" + node1Name + "-UUID", @@ -5882,14 +6103,16 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" }, expectedNAT, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1Name, - UUID: types.GWRouterPrefix + node1Name + "-UUID", + Name: types.GWRouterPrefix + node1Name, + UUID: types.GWRouterPrefix + node1Name + "-UUID", + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2Name, - UUID: types.GWRouterPrefix + node2Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, - Nat: []string{"egressip-nat-UUID"}, + Name: types.GWRouterPrefix + node2Name, + UUID: types.GWRouterPrefix + node2Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, + Nat: []string{"egressip-nat-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: "k8s-" + node1Name + "-UUID", @@ -5978,14 +6201,16 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" Networks: []string{node2LogicalRouterIfAddrV6}, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1Name, - UUID: types.GWRouterPrefix + node1Name + "-UUID", + Name: types.GWRouterPrefix + node1Name, + UUID: types.GWRouterPrefix + node1Name + "-UUID", + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2Name, - UUID: types.GWRouterPrefix + node2Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, - Nat: []string{}, + Name: types.GWRouterPrefix + node2Name, + UUID: types.GWRouterPrefix + node2Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node2Name + "-UUID"}, + Nat: []string{}, + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: "k8s-" + node1Name + "-UUID", @@ -6078,6 +6303,14 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" Name: node2Name, Ports: []string{"k8s-" + node2Name + "-UUID"}, } + dynamicNeighRouters := "true" + if config.OVNKubernetesFeature.EnableInterconnect { + dynamicNeighRouters = "false" + } + + logicalRouterOptions := map[string]string{ + "dynamic_neigh_routers": dynamicNeighRouters, + } fakeOvn.startWithDBSetup(libovsdbtest.TestSetup{ NBData: []libovsdbtest.TestData{ &nbdb.LogicalRouter{ @@ -6085,12 +6318,14 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" UUID: types.OVNClusterRouter + "-UUID", }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1.Name, - UUID: types.GWRouterPrefix + node1.Name + "-UUID", + Name: types.GWRouterPrefix + node1.Name, + UUID: types.GWRouterPrefix + node1.Name + "-UUID", + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2.Name, - UUID: types.GWRouterPrefix + node2.Name + "-UUID", + Name: types.GWRouterPrefix + node2.Name, + UUID: types.GWRouterPrefix + node2.Name + "-UUID", + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: types.EXTSwitchToGWRouterPrefix + types.GWRouterPrefix + node1Name + "-UUID", @@ -6204,12 +6439,14 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" ExternalIDs: getEgressIPLRPNoReRoutePodToJoinDbIDs(IPFamilyValueV4, types.DefaultNetworkName, fakeOvn.controller.eIPC.controllerName).GetExternalIDs(), }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1.Name, - UUID: types.GWRouterPrefix + node1.Name + "-UUID", + Name: types.GWRouterPrefix + node1.Name, + UUID: types.GWRouterPrefix + node1.Name + "-UUID", + Options: logicalRouterOptions, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node2.Name, - UUID: types.GWRouterPrefix + node2.Name + "-UUID", + Name: types.GWRouterPrefix + node2.Name, + UUID: types.GWRouterPrefix + node2.Name + "-UUID", + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: types.EXTSwitchToGWRouterPrefix + types.GWRouterPrefix + node1Name + "-UUID", @@ -6279,7 +6516,14 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" util.OVNNodeHostCIDRs: fmt.Sprintf("[\"%s\"]", nodeIPv4), } node := getNodeObj("node", annotations, map[string]string{}) + dynamicNeighRouters := "true" + if config.OVNKubernetesFeature.EnableInterconnect { + dynamicNeighRouters = "false" + } + logicalRouterOptions := map[string]string{ + "dynamic_neigh_routers": dynamicNeighRouters, + } fakeOvn.startWithDBSetup(libovsdbtest.TestSetup{ NBData: []libovsdbtest.TestData{ &nbdb.LogicalRouter{ @@ -6287,8 +6531,9 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" UUID: types.OVNClusterRouter + "-UUID", }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node.Name, - UUID: types.GWRouterPrefix + node.Name + "-UUID", + Name: types.GWRouterPrefix + node.Name, + UUID: types.GWRouterPrefix + node.Name + "-UUID", + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: types.EXTSwitchToGWRouterPrefix + types.GWRouterPrefix + nodeName + "UUID", @@ -6380,8 +6625,9 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" ExternalIDs: getEgressIPLRPNoReRoutePodToJoinDbIDs(IPFamilyValueV4, types.DefaultNetworkName, fakeOvn.controller.eIPC.controllerName).GetExternalIDs(), }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node.Name, - UUID: types.GWRouterPrefix + node.Name + "-UUID", + Name: types.GWRouterPrefix + node.Name, + UUID: types.GWRouterPrefix + node.Name + "-UUID", + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: types.EXTSwitchToGWRouterPrefix + types.GWRouterPrefix + nodeName + "UUID", @@ -6468,7 +6714,14 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" Name: node1.Name, Ports: []string{"k8s-" + node1.Name + "-UUID"}, } + dynamicNeighRouters := "true" + if config.OVNKubernetesFeature.EnableInterconnect { + dynamicNeighRouters = "false" + } + logicalRouterOptions := map[string]string{ + "dynamic_neigh_routers": dynamicNeighRouters, + } fakeOvn.startWithDBSetup( libovsdbtest.TestSetup{ NBData: []libovsdbtest.TestData{ @@ -6477,9 +6730,10 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" UUID: types.OVNClusterRouter + "-UUID", }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1.Name, - UUID: types.GWRouterPrefix + node1.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Name: types.GWRouterPrefix + node1.Name, + UUID: types.GWRouterPrefix + node1.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouterPort{ UUID: types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID", @@ -6591,10 +6845,11 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" "default-no-reroute-node-UUID", "default-no-reroute-reply-traffic"}, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1.Name, - UUID: types.GWRouterPrefix + node1.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, - Nat: []string{"egressip-nat-UUID1"}, + Name: types.GWRouterPrefix + node1.Name, + UUID: types.GWRouterPrefix + node1.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Nat: []string{"egressip-nat-UUID1"}, + Options: logicalRouterOptions, }, &nbdb.NAT{ UUID: "egressip-nat-UUID1", @@ -6699,10 +6954,11 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" Policies: []string{"no-reroute-UUID", "no-reroute-service-UUID", "default-no-reroute-node-UUID", "default-no-reroute-reply-traffic"}, }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1.Name, - UUID: types.GWRouterPrefix + node1.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, - Nat: []string{}, + Name: types.GWRouterPrefix + node1.Name, + UUID: types.GWRouterPrefix + node1.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Nat: []string{}, + Options: logicalRouterOptions, }, &nbdb.LogicalSwitchPort{ UUID: types.EXTSwitchToGWRouterPrefix + types.GWRouterPrefix + node1Name + "-UUID", @@ -6813,7 +7069,14 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" Name: node1.Name, Ports: []string{"k8s-" + node1.Name + "-UUID"}, } + dynamicNeighRouters := "true" + if config.OVNKubernetesFeature.EnableInterconnect { + dynamicNeighRouters = "false" + } + logicalRouterOptions := map[string]string{ + "dynamic_neigh_routers": dynamicNeighRouters, + } fakeOvn.startWithDBSetup( libovsdbtest.TestSetup{ NBData: []libovsdbtest.TestData{ @@ -6822,9 +7085,10 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" UUID: types.OVNClusterRouter + "-UUID", }, &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1.Name, - UUID: types.GWRouterPrefix + node1.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Name: types.GWRouterPrefix + node1.Name, + UUID: types.GWRouterPrefix + node1.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Options: logicalRouterOptions, }, &nbdb.LogicalRouterPort{ UUID: types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID", @@ -6903,10 +7167,11 @@ var _ = ginkgo.Describe("OVN master EgressIP Operations cluster default network" UUID: "reroute-UUID1", } node1GR := &nbdb.LogicalRouter{ - Name: types.GWRouterPrefix + node1.Name, - UUID: types.GWRouterPrefix + node1.Name + "-UUID", - Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, - Nat: []string{"egressip-nat-UUID1"}, + Name: types.GWRouterPrefix + node1.Name, + UUID: types.GWRouterPrefix + node1.Name + "-UUID", + Ports: []string{types.GWRouterToJoinSwitchPrefix + types.GWRouterPrefix + node1.Name + "-UUID"}, + Nat: []string{"egressip-nat-UUID1"}, + Options: logicalRouterOptions, } nodeSwitch.QOSRules = []string{"default-QoS-UUID"} diff --git a/go-controller/pkg/ovn/gateway.go b/go-controller/pkg/ovn/gateway.go index 5af52e533e..d9195f86db 100644 --- a/go-controller/pkg/ovn/gateway.go +++ b/go-controller/pkg/ovn/gateway.go @@ -276,9 +276,14 @@ func (gw *GatewayManager) GatewayInit( physicalIPs[i] = ip.IP.String() } + dynamicNeighRouters := "true" + if config.OVNKubernetesFeature.EnableInterconnect { + dynamicNeighRouters = "false" + } + logicalRouterOptions := map[string]string{ "always_learn_from_arp_request": "false", - "dynamic_neigh_routers": "true", + "dynamic_neigh_routers": dynamicNeighRouters, "chassis": l3GatewayConfig.ChassisID, "lb_force_snat_ip": "router_ip", "mac_binding_age_threshold": types.GRMACBindingAgeThreshold, diff --git a/go-controller/pkg/ovn/gateway_test.go b/go-controller/pkg/ovn/gateway_test.go index 6bcd3ea52e..cc5c96ae61 100644 --- a/go-controller/pkg/ovn/gateway_test.go +++ b/go-controller/pkg/ovn/gateway_test.go @@ -248,6 +248,11 @@ func generateGatewayInitExpectedNB(testData []libovsdbtest.TestData, expectedOVN } testData = append(testData, copp) + dynamicNeighRouters := "true" + if config.OVNKubernetesFeature.EnableInterconnect { + dynamicNeighRouters = "false" + } + testData = append(testData, &nbdb.LogicalRouter{ UUID: GRName + "-UUID", Name: GRName, @@ -255,7 +260,7 @@ func generateGatewayInitExpectedNB(testData []libovsdbtest.TestData, expectedOVN "lb_force_snat_ip": "router_ip", "snat-ct-zone": "0", "always_learn_from_arp_request": "false", - "dynamic_neigh_routers": "true", + "dynamic_neigh_routers": dynamicNeighRouters, "chassis": l3GatewayConfig.ChassisID, "mac_binding_age_threshold": types.GRMACBindingAgeThreshold, }, @@ -465,6 +470,13 @@ var _ = ginkgo.Describe("Gateway Init Operations", func() { LogicalPort: types.GWRouterToExtSwitchPrefix + types.GWRouterPrefix + nodeName, } GRName := "GR_" + nodeName + + dynamicNeighRouters := "true" + + if config.OVNKubernetesFeature.EnableInterconnect { + dynamicNeighRouters = "false" + } + expectedOVNGatewayRouter := &nbdb.LogicalRouter{ UUID: GRName + "-UUID", Name: GRName, @@ -472,7 +484,7 @@ var _ = ginkgo.Describe("Gateway Init Operations", func() { "lb_force_snat_ip": "router_ip", "snat-ct-zone": "0", "always_learn_from_arp_request": "false", - "dynamic_neigh_routers": "true", + "dynamic_neigh_routers": dynamicNeighRouters, "mac_binding_age_threshold": types.GRMACBindingAgeThreshold, }, StaticRoutes: []string{routeUUID}, @@ -573,6 +585,12 @@ var _ = ginkgo.Describe("Gateway Init Operations", func() { LogicalPort: types.GWRouterToExtSwitchPrefix + types.GWRouterPrefix + nodeName, } GRName := "GR_" + nodeName + + dynamicNeighRouters := "true" + if config.OVNKubernetesFeature.EnableInterconnect { + dynamicNeighRouters = "false" + } + expectedOVNGatewayRouter := &nbdb.LogicalRouter{ UUID: GRName + "-UUID", Name: GRName, @@ -580,7 +598,7 @@ var _ = ginkgo.Describe("Gateway Init Operations", func() { "lb_force_snat_ip": "router_ip", "snat-ct-zone": "0", "always_learn_from_arp_request": "false", - "dynamic_neigh_routers": "true", + "dynamic_neigh_routers": dynamicNeighRouters, "mac_binding_age_threshold": types.GRMACBindingAgeThreshold, }, StaticRoutes: []string{routeUUID}, diff --git a/go-controller/pkg/ovn/gress_policy.go b/go-controller/pkg/ovn/gress_policy.go index ee93ba8b72..e362e1b898 100644 --- a/go-controller/pkg/ovn/gress_policy.go +++ b/go-controller/pkg/ovn/gress_policy.go @@ -14,6 +14,7 @@ import ( "github.com/ovn-org/ovn-kubernetes/go-controller/pkg/types" "github.com/ovn-org/ovn-kubernetes/go-controller/pkg/util" + v1 "k8s.io/api/core/v1" knet "k8s.io/api/networking/v1" utilnet "k8s.io/utils/net" ) @@ -102,12 +103,16 @@ func (gp *gressPolicy) addPeerAddressSets(asHashNameV4, asHashNameV6 string) { // If the port is not specified, it implies all ports for that protocol func (gp *gressPolicy) addPortPolicy(portJSON *knet.NetworkPolicyPort) { var pp *libovsdbutil.NetworkPolicyPort + protocol := v1.ProtocolTCP + if portJSON.Protocol != nil { + protocol = *portJSON.Protocol + } if portJSON.Port != nil && portJSON.EndPort != nil { - pp = libovsdbutil.GetNetworkPolicyPort(*portJSON.Protocol, portJSON.Port.IntVal, *portJSON.EndPort) + pp = libovsdbutil.GetNetworkPolicyPort(protocol, portJSON.Port.IntVal, *portJSON.EndPort) } else if portJSON.Port != nil { - pp = libovsdbutil.GetNetworkPolicyPort(*portJSON.Protocol, portJSON.Port.IntVal, 0) + pp = libovsdbutil.GetNetworkPolicyPort(protocol, portJSON.Port.IntVal, 0) } else { - pp = libovsdbutil.GetNetworkPolicyPort(*portJSON.Protocol, 0, 0) + pp = libovsdbutil.GetNetworkPolicyPort(protocol, 0, 0) } gp.portPolicies = append(gp.portPolicies, pp) } diff --git a/go-controller/pkg/ovn/policy_test.go b/go-controller/pkg/ovn/policy_test.go index 5edb74f7f5..bd5512cac4 100644 --- a/go-controller/pkg/ovn/policy_test.go +++ b/go-controller/pkg/ovn/policy_test.go @@ -540,8 +540,7 @@ func getPortNetworkPolicy(policyName, namespace, labelName, labelVal string, tcp }, []knet.NetworkPolicyIngressRule{{ Ports: []knet.NetworkPolicyPort{{ - Port: &intstr.IntOrString{IntVal: tcpPort}, - Protocol: &tcpProtocol, + Port: &intstr.IntOrString{IntVal: tcpPort}, }}, }}, []knet.NetworkPolicyEgressRule{{ diff --git a/go-controller/pkg/ovn/secondary_layer3_network_controller_test.go b/go-controller/pkg/ovn/secondary_layer3_network_controller_test.go index 3a63953a0f..310d4f3486 100644 --- a/go-controller/pkg/ovn/secondary_layer3_network_controller_test.go +++ b/go-controller/pkg/ovn/secondary_layer3_network_controller_test.go @@ -1015,12 +1015,18 @@ func gwRouterJoinIPAddress() *net.IPNet { } func gwRouterOptions(gwConfig util.L3GatewayConfig) map[string]string { + + dynamicNeighRouters := "true" + if config.OVNKubernetesFeature.EnableInterconnect { + dynamicNeighRouters = "false" + } + return map[string]string{ "lb_force_snat_ip": "router_ip", "mac_binding_age_threshold": "300", "chassis": gwConfig.ChassisID, "always_learn_from_arp_request": "false", - "dynamic_neigh_routers": "true", + "dynamic_neigh_routers": dynamicNeighRouters, } } diff --git a/test/e2e/e2e.go b/test/e2e/e2e.go index 6cda27fc81..4f534e4fe0 100644 --- a/test/e2e/e2e.go +++ b/test/e2e/e2e.go @@ -613,7 +613,7 @@ func restartOVNKubeNodePod(clientset kubernetes.Interface, namespace string, nod return fmt.Errorf("could not find ovnkube-node pod running on node %s", nodeName) } for _, pod := range ovnKubeNodePods.Items { - if err := e2epod.DeletePodWithWait(context.TODO(), clientset, &pod); err != nil { + if err := deletePodWithWait(context.TODO(), clientset, &pod); err != nil { return fmt.Errorf("could not delete ovnkube-node pod on node %s: %w", nodeName, err) } } @@ -852,7 +852,7 @@ var _ = ginkgo.Describe("e2e control plane", func() { } ginkgo.By("Deleting ovnkube control plane pod " + podName) - e2epod.DeletePodWithWaitByName(context.TODO(), f.ClientSet, podName, ovnNamespace) + deletePodWithWaitByName(context.TODO(), f.ClientSet, podName, ovnNamespace) framework.Logf("Deleted ovnkube control plane pod %q", podName) ginkgo.By("Ensuring there were no connectivity errors") @@ -898,7 +898,8 @@ var _ = ginkgo.Describe("e2e control plane", func() { !strings.HasPrefix(pod.Name, "ovnkube-identity") && !strings.HasPrefix(pod.Name, "ovs-node") { framework.Logf("%q", pod.Namespace) - e2epod.DeletePodWithWaitByName(context.TODO(), f.ClientSet, pod.Name, ovnNamespace) + err = deletePodWithWaitByName(context.TODO(), f.ClientSet, pod.Name, ovnNamespace) + framework.ExpectNoError(err, fmt.Sprintf("failed to delete pod %s", pod.Name)) framework.Logf("Deleted control plane pod %q", pod.Name) } } @@ -931,7 +932,8 @@ var _ = ginkgo.Describe("e2e control plane", func() { for _, pod := range podList.Items { if strings.HasPrefix(pod.Name, controlPlanePodName) && !strings.HasPrefix(pod.Name, "ovs-node") { framework.Logf("%q", pod.Namespace) - e2epod.DeletePodWithWaitByName(context.TODO(), f.ClientSet, pod.Name, ovnNamespace) + err = deletePodWithWaitByName(context.TODO(), f.ClientSet, pod.Name, ovnNamespace) + framework.ExpectNoError(err, fmt.Sprintf("failed to delete pod %s", pod.Name)) framework.Logf("Deleted control plane pod %q", pod.Name) } } @@ -1009,11 +1011,12 @@ var _ = ginkgo.Describe("e2e control plane", func() { } framework.Failf("could not restart ovnkube-node pod: %s", err) } - node, err := f.ClientSet.CoreV1().Nodes().Get(context.TODO(), testNodeName, metav1.GetOptions{ResourceVersion: "0"}) - if err != nil { - framework.Failf("could not find node resource: %s", err) - } + gomega.Eventually(func() bool { + node, err := f.ClientSet.CoreV1().Nodes().Get(context.TODO(), testNodeName, metav1.GetOptions{ResourceVersion: "0"}) + if err != nil { + framework.Failf("could not find node resource: %s", err) + } return e2enode.IsNodeReady(node) }, 30*time.Second).Should(gomega.BeFalse()) }) @@ -1031,11 +1034,11 @@ var _ = ginkgo.Describe("e2e control plane", func() { } // validate that node is in Ready state - node, err := f.ClientSet.CoreV1().Nodes().Get(context.TODO(), testNodeName, metav1.GetOptions{ResourceVersion: "0"}) - if err != nil { - framework.Failf("could not find node resource: %s", err) - } gomega.Eventually(func() bool { + node, err := f.ClientSet.CoreV1().Nodes().Get(context.TODO(), testNodeName, metav1.GetOptions{ResourceVersion: "0"}) + if err != nil { + framework.Failf("could not find node resource: %s", err) + } return e2enode.IsNodeReady(node) }, 30*time.Second).Should(gomega.BeTrue()) }) @@ -2185,8 +2188,10 @@ var _ = ginkgo.Describe("e2e delete databases", func() { var ( command = []string{"/agnhost", "netexec", fmt.Sprintf("--http-port=" + port)} ) - createGenericPod(f, pod1Name, node1Name, f.Namespace.Name, command) - createGenericPod(f, pod2Name, node2Name, f.Namespace.Name, command) + _, err := createGenericPod(f, pod1Name, node1Name, f.Namespace.Name, command) + framework.ExpectNoError(err, "failed to create pod %s/%s", f.Namespace.Name, pod1Name) + _, err = createGenericPod(f, pod2Name, node2Name, f.Namespace.Name, command) + framework.ExpectNoError(err, "failed to create pod %s/%s", f.Namespace.Name, pod2Name) pod2IP := getPodAddress(pod2Name, f.Namespace.Name) @@ -2339,7 +2344,8 @@ var _ = ginkgo.Describe("e2e delete databases", func() { } framework.Logf("wait for all the Deployment to become ready again after pod deletion") - e2edeployment.WaitForDeploymentComplete(f.ClientSet, dbDeployment) + err = e2edeployment.WaitForDeploymentComplete(f.ClientSet, dbDeployment) + framework.ExpectNoError(err, "failed to wait for DB deployment to complete") framework.Logf("all the pods finish full restart") diff --git a/test/e2e/egress_firewall.go b/test/e2e/egress_firewall.go index 1e941b650c..529f3dc034 100644 --- a/test/e2e/egress_firewall.go +++ b/test/e2e/egress_firewall.go @@ -23,7 +23,6 @@ import ( "k8s.io/kubernetes/test/e2e/framework" e2ekubectl "k8s.io/kubernetes/test/e2e/framework/kubectl" e2enode "k8s.io/kubernetes/test/e2e/framework/node" - e2epod "k8s.io/kubernetes/test/e2e/framework/pod" utilnet "k8s.io/utils/net" ) @@ -171,12 +170,7 @@ var _ = ginkgo.Describe("e2e egress firewall policy validation", func() { return } } - err := e2epod.DeletePodWithWait(context.TODO(), f.ClientSet, &v1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: f.Namespace.Name, - Name: podName, - }, - }) + err := deletePodWithWaitByName(context.TODO(), f.ClientSet, podName, f.Namespace.Name) gomega.Expect(err).NotTo(gomega.HaveOccurred()) } framework.Failf("Failed to create pod %s that can reach %s:%d after %d retries", podName, reachableDst, reachablePort, retries) @@ -408,6 +402,27 @@ spec: "by the external firewall policy", externalContainer1IP)) checkConnectivity(srcPodName, externalContainer1IP, externalContainerPort1, false) }) + + ginkgo.It("Should validate that egressfirewall supports DNS name in caps", func() { + // egress firewall crd yaml configuration + var egressFirewallConfig = fmt.Sprintf(`kind: EgressFirewall +apiVersion: k8s.ovn.org/v1 +metadata: + name: default + namespace: %s +spec: + egress: + - type: Allow + to: + dnsName: WWW.TEST.COM + - type: Deny + to: + cidrSelector: %s +`, f.Namespace.Name, denyAllCIDR) + applyEF(egressFirewallConfig, f.Namespace.Name) + framework.Logf("Deleting EgressFirewall in namespace %s", f.Namespace.Name) + e2ekubectl.RunKubectlOrDie(f.Namespace.Name, "delete", "egressfirewall", "default") + }) }) table.DescribeTable("Should validate the egress firewall policy functionality against cluster nodes by using node selector", diff --git a/test/e2e/external_gateways.go b/test/e2e/external_gateways.go index c618552e64..8b4f0284a3 100644 --- a/test/e2e/external_gateways.go +++ b/test/e2e/external_gateways.go @@ -25,7 +25,6 @@ import ( "k8s.io/kubernetes/test/e2e/framework" e2ekubectl "k8s.io/kubernetes/test/e2e/framework/kubectl" e2enode "k8s.io/kubernetes/test/e2e/framework/node" - e2epod "k8s.io/kubernetes/test/e2e/framework/pod" "k8s.io/kubernetes/test/e2e/framework/skipper" utilnet "k8s.io/utils/net" ) @@ -176,7 +175,8 @@ var _ = ginkgo.Describe("External Gateway", func() { framework.Failf("failed to add the loopback ip to dev lo on the test container: %v", err) } // Create the pod that will be used as the source for the connectivity test - createGenericPod(f, srcPingPodName, ciWorkerNodeSrc, f.Namespace.Name, command) + _, err = createGenericPod(f, srcPingPodName, ciWorkerNodeSrc, f.Namespace.Name, command) + framework.ExpectNoError(err, "failed to create pod %s/%s", f.Namespace.Name, srcPingPodName) // wait for pod setup to return a valid address err = wait.PollImmediate(retryInterval, retryTimeout, func() (bool, error) { pingSrc = getPodAddress(srcPingPodName, f.Namespace.Name) @@ -349,7 +349,8 @@ var _ = ginkgo.Describe("External Gateway", func() { framework.Logf("the pod cidr for node %s is %s", workerNodeInfo.name, podCIDR) // Create the pod that will be used as the source for the connectivity test - createGenericPod(f, dstPingPodName, workerNodeInfo.name, f.Namespace.Name, command) + _, err = createGenericPod(f, dstPingPodName, workerNodeInfo.name, f.Namespace.Name, command) + framework.ExpectNoError(err, "failed to create pod %s/%s", f.Namespace.Name, dstPingPodName) // wait for the pod setup to return a valid address err = wait.PollImmediate(retryInterval, retryTimeout, func() (bool, error) { pingDstPod = getPodAddress(dstPingPodName, f.Namespace.Name) @@ -1505,7 +1506,8 @@ var _ = ginkgo.Describe("External Gateway", func() { // https://github.com/ovn-org/ovn-kubernetes/pull/4114#issuecomment-1940916326 // TODO(trozet) change this back to 2 gateways once github actions kernel is updated ginkgo.By(fmt.Sprintf("Reducing to one gateway. Removing gateway: %s", gatewayPodName2)) - e2epod.DeletePodWithWaitByName(context.TODO(), f.ClientSet, gatewayPodName2, servingNamespace) + err := deletePodWithWaitByName(context.TODO(), f.ClientSet, gatewayPodName2, servingNamespace) + framework.ExpectNoError(err, "failed to delete pod %s/%s", servingNamespace, gatewayPodName2) time.Sleep(1 * time.Second) ginkgo.By("Checking if one of the external gateways are reachable via Egress") diff --git a/test/e2e/multi_node_zones_interconnect.go b/test/e2e/multi_node_zones_interconnect.go index dfdaf60ead..492a67b55a 100644 --- a/test/e2e/multi_node_zones_interconnect.go +++ b/test/e2e/multi_node_zones_interconnect.go @@ -158,22 +158,27 @@ var _ = ginkgo.Describe("Multi node zones interconnect", func() { e2epod.NewPodClient(fr).CreateSync(context.TODO(), clientPod) ginkgo.By("asserting the *client* pod can contact the server pod exposed endpoint") - checkPodsInterconnectivity(clientPod, serverPod, fr.Namespace.Name, cs) + err := checkPodsInterconnectivity(clientPod, serverPod, fr.Namespace.Name, cs) + framework.ExpectNoError(err, "failed to check pods interconnectivity") // Change the zone of client-pod node to that of server-pod node s := fmt.Sprintf("Changing the client-pod node %s zone from %s to %s", clientPodNodeName, clientPodNodeZone, serverPodNodeZone) ginkgo.By(s) - changeNodeZone(clientPodNode, serverPodNodeZone, cs) + err = changeNodeZone(clientPodNode, serverPodNodeZone, cs) + framework.ExpectNoError(err, "failed to change node zone") ginkgo.By("Checking that the client-pod can connect to the server pod when they are in same zone") - checkPodsInterconnectivity(clientPod, serverPod, fr.Namespace.Name, cs) + err = checkPodsInterconnectivity(clientPod, serverPod, fr.Namespace.Name, cs) + framework.ExpectNoError(err, "failed to check pods interconnectivity") // Change back the zone of client-pod node s = fmt.Sprintf("Changing back the client-pod node %s zone from %s to %s", clientPodNodeName, serverPodNodeZone, clientPodNodeZone) ginkgo.By(s) - changeNodeZone(clientPodNode, clientPodNodeZone, cs) + err = changeNodeZone(clientPodNode, clientPodNodeZone, cs) + framework.ExpectNoError(err, "failed to change node zone") ginkgo.By("Checking again that the client-pod can connect to the server-pod when they are in different zone") - checkPodsInterconnectivity(clientPod, serverPod, fr.Namespace.Name, cs) + err = checkPodsInterconnectivity(clientPod, serverPod, fr.Namespace.Name, cs) + framework.ExpectNoError(err, "failed to check pods interconnectivity") }) }) diff --git a/test/e2e/node_ip_mac_migration.go b/test/e2e/node_ip_mac_migration.go index 7865af05cf..68d5e0d654 100644 --- a/test/e2e/node_ip_mac_migration.go +++ b/test/e2e/node_ip_mac_migration.go @@ -235,7 +235,7 @@ spec: return isOVNEncapIPReady(workerNode.Name, workerNodeIPs[ipAddrFamily], ovnkubePodWorkerNode.Name) }, pollingTimeout, pollingInterval).Should(BeTrue()) - err = e2epod.DeletePodWithWait(context.TODO(), f.ClientSet, &ovnkubePodWorkerNode) + err = deletePodWithWait(context.TODO(), f.ClientSet, &ovnkubePodWorkerNode) Expect(err).NotTo(HaveOccurred()) By(fmt.Sprintf("Sleeping for %d seconds to give things time to settle", settleTimeout)) @@ -555,7 +555,8 @@ spec: JustAfterEach(func() { if len(workerNodeMAC) > 0 { By("Reverting to original MAC address") - setMACAddress(ovnkPod, workerNodeMAC.String()) + err := setMACAddress(ovnkPod, workerNodeMAC.String()) + framework.ExpectNoError(err, "failed to revert MAC address") } }) diff --git a/test/e2e/util.go b/test/e2e/util.go index 18349b5382..e749827af2 100644 --- a/test/e2e/util.go +++ b/test/e2e/util.go @@ -17,6 +17,7 @@ import ( "github.com/ovn-org/ovn-kubernetes/go-controller/pkg/util" v1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" utilerrors "k8s.io/apimachinery/pkg/util/errors" @@ -1337,3 +1338,68 @@ func matchIPv4StringFamily(ipStrings []string) (string, error) { func matchIPv6StringFamily(ipStrings []string) (string, error) { return util.MatchIPStringFamily(true /*ipv6*/, ipStrings) } + +// This is a replacement for e2epod.DeletePodWithWait(), which does not handle pods that +// may be automatically restarted (https://issues.k8s.io/126785) +func deletePodWithWait(ctx context.Context, c clientset.Interface, pod *v1.Pod) error { + if pod == nil { + return nil + } + if pod.UID == "" { + // We only recurse into deletePodWithWaitByName when UID is *not* set, to + // avoid infinite loops. + return deletePodWithWaitByName(ctx, c, pod.Name, pod.Namespace) + } + + framework.Logf("Deleting pod %q in namespace %q", pod.Name, pod.Namespace) + err := c.CoreV1().Pods(pod.Namespace).Delete(ctx, pod.Name, metav1.DeleteOptions{}) + if err != nil { + if apierrors.IsNotFound(err) { + return nil // assume pod was already deleted + } + return fmt.Errorf("pod Delete API error: %w", err) + } + framework.Logf("Wait up to %v for pod %q to be fully deleted", e2epod.PodDeleteTimeout, pod.Name) + err = waitForPodNotFoundInNamespace(ctx, c, pod.Name, pod.Namespace, pod.UID, e2epod.PodDeleteTimeout) + if err != nil { + return fmt.Errorf("pod %q was not deleted: %w", pod.Name, err) + } + return nil +} + +// This is a replacement for e2epod.DeletePodWithWaitByName(), which does not handle pods +// that may be automatically restarted (https://issues.k8s.io/126785) +func deletePodWithWaitByName(ctx context.Context, c clientset.Interface, podName, podNamespace string) error { + pod, err := c.CoreV1().Pods(podNamespace).Get(ctx, podName, metav1.GetOptions{}) + if err != nil { + if apierrors.IsNotFound(err) { + return nil // assume pod was already deleted + } + return fmt.Errorf("pod Get API error: %w", err) + } + if pod.UID == "" { + return fmt.Errorf("unexpected Pod with no UID returned from API!") + } + // We only recurse into deletePodWithWait when UID *is* set, to avoid infinite + // loops. + return deletePodWithWait(ctx, c, pod) +} + +// This is an alternative version of e2epod.WaitForPodNotFoundInNamespace(), which takes +// a UID as well. +func waitForPodNotFoundInNamespace(ctx context.Context, c clientset.Interface, podName, ns string, uid types.UID, timeout time.Duration) error { + err := framework.Gomega().Eventually(ctx, framework.HandleRetry(func(ctx context.Context) (*v1.Pod, error) { + pod, err := c.CoreV1().Pods(ns).Get(ctx, podName, metav1.GetOptions{}) + if apierrors.IsNotFound(err) { + return nil, nil + } + if pod != nil && pod.UID != uid { + return nil, nil + } + return pod, err + })).WithTimeout(timeout).Should(gomega.BeNil()) + if err != nil { + return fmt.Errorf("expected pod to not be found: %w", err) + } + return nil +}