From 7bce740762f1f5da845fd989497c9f885e291557 Mon Sep 17 00:00:00 2001 From: Tim Rozet Date: Thu, 6 Jun 2024 22:23:33 -0400 Subject: [PATCH 1/6] Adds support for BGP in OVNK Signed-off-by: Tim Rozet --- enhancements/network/bgp-ovn-kubernetes.md | 685 ++++++++++++++++++ .../images/bgp_novpn_advertisements.png | Bin 0 -> 66996 bytes enhancements/network/images/vrf-lite.png | Bin 0 -> 77212 bytes 3 files changed, 685 insertions(+) create mode 100644 enhancements/network/bgp-ovn-kubernetes.md create mode 100644 enhancements/network/images/bgp_novpn_advertisements.png create mode 100644 enhancements/network/images/vrf-lite.png diff --git a/enhancements/network/bgp-ovn-kubernetes.md b/enhancements/network/bgp-ovn-kubernetes.md new file mode 100644 index 0000000000..ea67b2699d --- /dev/null +++ b/enhancements/network/bgp-ovn-kubernetes.md @@ -0,0 +1,685 @@ +--- +title: bgp-ovn-kubernetes +authors: + - "@trozet" + - "@fedepaol" +reviewers: + - "@tssurya" + - "@jcaamano" + - "@cybertron" + - "@msherif1234" + - "@cgoncalves" +approvers: + - "@jcaamano" +api-approvers: + - "None" +creation-date: 2024-06-06 +last-updated: 2024-06-06 +tracking-link: + - https://issues.redhat.com/browse/SDN-4975 +see-also: + - "/enhancements/bgp-overview.md" +--- + +# OVN-Kubernetes BGP Integration + +## Summary + +OVN-Kubernetes currently has no native routing protocol integration, and relies on a Geneve overlay for east/west +traffic, as well as third party operators to handle external network integration into the cluster. The purpose of this +enhancement is to introduce BGP as a supported routing protocol with OVN-Kubernetes. The extent of this support will +allow OVN-Kubernetes to integrate into different BGP user environments, enabling it to dynamically expose cluster scoped +network entities into a provider’s network, as well as program BGP learned routes from the provider’s network into OVN. + +## Motivation + +There are multiple driving factors which necessitate integrating BGP into OVN-Kubernetes. They will be broken down into +sections below, describing each use case/requirement. Additionally, implementing BGP paves the way for full EVPN support +in the future, which is the choice of networking fabric in the modern data center. For purposes of this document, the +external, physical network of the cluster which a user administers will be called the “provider network”. + +### Importing Routes from the Provider Network + +Today in OpenShift there is no API for a user to be able to configure routes into OVN. In order for a user to change how +cluster traffic is routed egress into the cluster, the user leverages local gateway mode, which forces egress traffic to +hop through the Linux host networking stack. There a user can configure routes inside the host via NM State. This +manual configuration would need to be performed and maintained across nodes and VRFs within each node. + +Additionally, if a user chooses to not manage routes within the host for local gateway mode, or the user chooses shared +gateway mode, then by default traffic is always sent to the default gateway. The only other way to affect egress routing +is by using the Multiple External Gateways (MEG) feature. With this feature the user may choose to have multiple +different egress gateways per namespace to send traffic to. + +As an alternative, configuring BGP peers and which route-targets to import would eliminate the need to manually +configure routes in the host, and would allow dynamic routing updates based on changes in the provider’s network. + +### Exporting Routes into the Provider Network + +There exists a need for provider networks to learn routes directly to services and pods today in Kubernetes. More +specifically, MetalLB is already one solution where load balancer IPs are advertised by BGP to provider networks. The +goal of this RFE is to not duplicate or replace the function of MetalLB. MetalLB should be able to interoperate with +OVN-Kubernetes, and be responsible for advertising services to a provider’s network. + +However, there is an alternative need to advertise pod IPs on the provider network. One use case is integration with 3rd +party load balancers, where they terminate a load balancer and then send packets directly to OCP nodes with the +destination IP address being the pod IP itself. Today these load balancers rely on custom operators to detect which node +a pod is scheduled to and then add routes into its load balancer to send the packet to the right node. + +By integrating BGP and advertising the pod subnets/addresses directly on the provider network, load balancers and other +entities on the network would be able to reach the pod IPs directly. + +### Datapath Performance + +In cases where throughput is a priority, using the underlay directly can eliminate the need for tunnel encapsulation, +and thus reducing the overhead and byte size of each packet. This allows for greater throughput. + +### Multi-homing, Link Redundancy, Fast Convergence + +BGP can use multi-homing with ECMP routing in order to provide layer 3 failover. When a link goes down, BGP can reroute +via a different path. This functionality can be coupled with BFD in order to provide fast failover. + +### User Stories + + * As a user I want to be able to leverage my existing BGP network to dynamically learn routes to pods in my Kubernetes + cluster. + * As a user, rather than having to maintain routes with NM State manually in each Kubernetes node, as well as being + constrained to using local gateway mode for respecting user defined routes; I want to use BGP so that I can dynamically + advertise egress routes for the Kubernetes pod traffic in either gateway mode. + * As a user where maximum throughput is a priority, I want to reduce packet overhead by not having to encapsulate + traffic with Geneve. + * As a baremetal or egress IP user, I do not want to have to restrict my nodes to the same layer 2 segment and prefer + to use a pure routing implementation to handle advertising virtual IP (VIP) movement across nodes. + +### Goals + +* To provide a user facing API to allow configuration of iBGP or eBGP peers, along typical BGP configuration including + communities, route filtering, etc. +* Support for advertising Egress IP addresses. +* To enable BFD to BGP peers. +* Leveraging BGP to allow for no overlay encapsulation with east/west traffic. +* ECMP routing support within OVN for BGP learned routes. +* Support for advertising user-defined networks via BGP as long as there is no subnet overlap over the default VRF. +* Allowing for VRF-Lite type of VPN where the user maps interfaces on the host to user-defined VRFs/networks and +advertises VPN routes via BGP sessions over said VRFs. + +### Non-Goals + +* Support of any other routing protocol. +* Running separate BGPd instances per VRF network. +* Providing any type of API or operator to automatically connect two Kubernetes clusters via L3VPN. +* Replacing the support that MetalLB provides today for advertising service IPs. +* Support for any other type of BGP speaker other than FRR. + +### Future Goals + +* Support EVPN configuration and integration with a user’s DC fabric, along with MAC-VRFs and IP-VRFs. + +## Proposal + +OVN-Kubernetes will leverage other projects that already exist to enable BGP in Linux. FRR will be used as the BGP +speaker and already has EVPN support for native Linux constructs like Linux bridges, VRF devices, VXLAN tunnels, etc. +FRR may need some code contributions to allow it to integrate with OVN and Open vSwitch. For FRR configuration, the +MetalLB project has already started an API to be able to configure FRR: +[https://github.com/metallb/frr-k8s](https://github.com/metallb/frr-k8s). While some of the configuration support for +FRR may be directly exposed by FRR-K8S API, it may also be the case that some intermediary CRD provided by +OVN-Kubernetes is required to integrate OVN-Kubernetes networking concepts into FRR. + +Functionally, FRR will handle advertising and importing routes and configuring those inside a Linux VRF. OVN-Kubernetes +will be responsible for listening on netlink and configuring OVN-Kubernetes logical routers with routes learned by FRR. + +### Workflow Description + +An admin has the ability to configure BGP peering and choose what networks to advertise. A tenant is able to define +networks for their namespace, but requires admin permission in order to expose those networks onto the provider's BGP +fabric. A typical workflow will be for a user or admin to create a user-defined network, and then the admin will be +responsible to: + +1. If setting up VRF-Lite, do any host modifications necessary via NMState to enslave a physical interface to the + matching network VRF. +2. Configure BGP peering via interacting with the FRR-K8S API for a given set of worker nodes. Also define filters for +what routes should be received from the provider network. +3. Create the OVN-Kubernetes RouteAdvertisements CR to configure what routes and where to advertise them. +4. Verify peering and that routes have been propagated correctly. +5. If desired, change the transport type from geneve on the network to none in order to no longer use an overlay. + +For detailed examples, see the [BGP Configuration](#bgp-configuration) section. + +### API Extensions +FRR-K8S API will be used in order to create BGP Peering and configure other BGP related configuration. A +RouteAdvertisements CRD will be introduced in order to determine which routes should be advertised for specific networks. +Additionally, the network CRD will be modified in order to expose a new transport field to determine if encapsulation +should be used for east/west traffic. + +### Topology Considerations + +#### Hypershift / Hosted Control Planes + +#### Standalone Clusters + +#### Single-node Deployments or MicroShift + +### Risks and Mitigations + +BGP has a wide range of configurations and configuration options that are supported by FRR today. There is a big risk +of scope creep to try to support all of these options during the initial development phase. During the initial release +the number of options supported will be limited to mitigate this issue, and the main focus will be on stability of a +default environment without enabling these extra options/features. + +Reliance on FRR is another minor risk, with no presence from the OCP networking team involved in that project. + +Another risk is integration with MetalLB. We need to ensure that MetalLB is still able to function correctly with +whatever OVN-Kubernetes is configuring within FRR. + +In addition, by dynamically learning routes and programming them into OVN, we risk a customer accidentally introducing +potentially hundreds or even thousands of routes into different OVN logical routers. As a mitigation, we can recommend +using communities or route aggregation to customers to limit RIB size. We will also need to scale test the effect of +many routes inside OVN logical routers. + +Also, FRR-K8S is not GA yet, and targeted for 4.17. + +### Drawbacks + +* Increased complexity of our SDN networking solution to support more complex networking. +* Increases support complexity due to integration with the a user's provider network. +* Increases network control plane load on nodes, as they have multiple peer connections and are having to maintain +a dynamic routing protocol. + +### Implementation Details/Notes/Constraints + +#### BGP Peering + +FRR-K8S shall support both internal BGP (iBGP) and external BGP (eBGP). With iBGP, a full mesh topology is required. This +can be cumbersome and have issues with scaling in large clusters. Therefore, FRR-K8S shall also support designating one +or more nodes as route reflectors. With route reflectors, nodes only have to connect to the route reflectors and do not +have to maintain a full mesh with all other nodes in the cluster. + +#### FRR-K8S Integration + +As previously mentioned frr-k8s will be used in order to deploy and manage FRR configuration. Support will be added +where necessary for gaps in frr-k8s API, but in the meantime frr-k8s supports also issuing raw FRR configuration. Every +attempt should be made to leverage the FRR-K8S API, and raw configuration should only be used as a last resort. A user +will need the ability to: + +* Define BGP peers, ASN, authentication, along with other common BGP configurations like communities, route filtering, etc. +* Configure BFD + +FRR-K8S will serve as the main API for user configuration of BGP via FRR-K8S CRs. OVN-Kubernetes will watch for these +CRs, and once created, OVN-Kubernetes will start monitoring the kernel routing table via netlink for routes installed +by FRR. When FRR is using Zebra, the routes can be identified via a proto "bgp" label: + +``` +123.123.123.0/24 nhid 47 via 172.18.0.5 dev breth0 proto bgp metric 20 +``` + +When these routes are seen on the node, ovnkube-controller will update the routes in NBDB for any GW routers on the +node, filtering the route for the GW router based on if the interface on the route matches the interface in OVS. This +will happen irrespective of gateway mode, as some features in local gateway mode rely on the GRs for sending traffic +(Egress IP, MEG). Note, this configuration will only happen on nodes selected by the FRR-K8S CRs. + +#### API Changes + +##### Route Advertisements + +When OVN-Kubernetes detects that a FRR-K8S CR has been created for BGP peering, OVN-Kubernetes will by default +advertise the pod subnet for each node, via creating an additive, per node FRR-K8S CR that is managed by OVN-Kubernetes. +OVN-Kubernetes CRD: + +```yaml +apiVersion: k8s.ovn.org/v1 +kind: RouteAdvertisements +metadata: + name: default +spec: + # networkSelector: + # nodeSelector: + targetVRF: default + advertisements: + podNetwork: true + egressIP: true + clusterIPs: true +``` + +In the above example, an optional networkSelector may also be optionally supplied which will match namespaces/networks. +When omitted, RouteAdvertisements will be applied to the default cluster network. If a selector is used that selects the +default cluster network, it will be enabled for any namespace using the cluster default network. Additionally, +advertisements may be limited to specific nodes via the nodeSelector. + +A networkSelector may select more than one network, including user-defined networks. In such a case the network subnets +will be checked by OVN-Kubernetes to determine if there is any overlap of the IP subnets. If so, an error status will be +reported to the CRD and no BGP configuration will be done by OVN-Kubernetes. + +The CRD will support enabling advertisements for pod subnet, egress IPs, as well as cluster IPs for services on the +selected networks. Note, MetalLB only handles advertising LoadBalancer IP and External IP so there is no conflict of +responsibilities here. + +The "targetVRF" key is used to determine which VRF the routes should be advertised in. The default value is "default", +which indicates the routes from the selected network should be advertised in the default VRF. Alternatively, the user +may specify the value "auto", in which case OVN-Kubernetes will advertise routes in the VRF that corresponds to the +selected network. + +##### No Tunnel/Overlay Mode + +Changes will be made to the network CRD(s) in order to specify the method of transport for east/west traffic. A new +field, “transport” will be added with values “geneve” or “none” (default geneve). The transport option in the CRD may be +used to toggle between using Geneve encapsulation (the default today) or using no encapsulation. With no encapsulation, +east/west packets are routed directly on the underlay using routing learned via BGP. This is supported for Layer 3 +networks only. Enabling a transport of “none” for Layer 2 networks will have no effect. Enabling a transport of “none” +without selecting all nodes for RouteAdvertisements will also break east/west traffic between those nodes, as there will +not be routes propagated into the BGP network for unselected nodes. Users should expect disruption when the transport of +a network is changed. + +#### BGP Configuration + +When OVN-Kubernetes detects that a FRRConfiguration has been created that has a corresponding and valid FRRNodeState, +OVN-Kubernetes will then use RouteAdvertisements CR create a corresponding FRRConfiguration. The following examples will +use an environment where a user has created an FRRConfiguration: + +```yaml +apiVersion: frrk8s.metallb.io/v1beta1 +kind: FRRConfiguration +metadata: + creationTimestamp: "2024-06-11T14:22:37Z" + generation: 1 + name: metallb-ovn-worker + namespace: metallb-system + resourceVersion: "1323" + uid: 99b64be3-4f36-4e0b-8704-75aa5182d89f +spec: + bgp: + routers: + - asn: 64512 + neighbors: + - address: 172.18.0.5 + asn: 64512 + disableMP: false + holdTime: 1m30s + keepaliveTime: 30s + passwordSecret: {} + port: 179 + toAdvertise: + allowed: + mode: filtered + toReceive: + allowed: + mode: filtered + nodeSelector: + matchLabels: + kubernetes.io/hostname: ovn-worker +``` + +OVNKube-Controller will check that if this FRRConfiguration applies to its node, ovn-worker. For this example, a user-defined +network named "blue", has been created with a network of 10.0.0.0/16, and a matching vrf exists in the Linux host. The slice +of this supernet that has been allocated to node ovn-worker is 10.0.1./0/24. + +##### Example 1: Advertising pod IPs from a user-defined network over BGP + +![](images/bgp_novpn_advertisements.png) + +In this example a user wants to expose network blue outside their OCP cluster so that pod IPs are reachable on the +external network. The admin has creates the following RouteAdvertisements CR for the blue tenant: +```yaml +apiVersion: k8s.ovn.org/v1 +kind: RouteAdvertisements +metadata: + name: default +spec: + advertisements: + podNetwork: true + networkSelector: + matchLabels: + k8s.ovn.org/metadata.name: blue + nodeSelector: + matchLabels: + kubernetes.io/hostname: ovn-worker +``` + +OVNKube-Controller will now see it needs to generate corresponding FRRConfiguration: + +```yaml +apiVersion: frrk8s.metallb.io/v1beta1 +kind: FRRConfiguration +metadata: + name: route-advertisements-blue + namespace: metallb-system +spec: + bgp: + routers: + - asn: 64512 + vrf: blue + prefixes: + - 10.0.1.0/24 + - asn: 64512 + neighbors: + - address: 172.18.0.5 + asn: 64512 + toAdvertise: + allowed: + prefixes: + - 10.0.1.0/24 + raw: + rawConfig: |- + router bgp 64512 + address-family ipv4 unicast + import vrf blue + exit-address-family + router bgp 64512 vrf blue + address-family ipv4 unicast + import vrf default + exit-address-family + nodeSelector: + matchLabels: + kubernetes.io/hostname: ovn-worker +``` + +In the above configuration generated by OVN-Kubernetes, the subnet 10.0.1.0/24 which belongs to VRF blue, is being +imported into the default VRF, and advertised to the 172.18.0.5 neighbor. This is because the targetVRF was defaulted so +the routes are leaked and advertised in the default VRF. Additionally, routes are being imported from the default VRF +into the blue VRF. + +##### Example 2: VRF Lite - Advertising pod IPs from a user-defined network over BGP with VPN + +![](images/vrf-lite.png) + +In this example, the user provisions a VLAN interface, enslaved to the VRF, which carries the blue network in isolation +to the external PE router. This provides a VRF-Lite design where FRR-K8S is going to be leveraged to advertise the blue +network only over the corresponding VRF/VLAN link to the next hop PE router. The same is done for the red tenant. +Here the user has created an additional FRRConfiguration CR to peer with the PE router on the blue and red VLANs: + +```yaml +apiVersion: frrk8s.metallb.io/v1beta1 +kind: FRRConfiguration +metadata: + name: vpn-ovn-worker + namespace: metallb-system +spec: + bgp: + routers: + - asn: 64512 + vrf: blue + neighbors: + - address: 182.18.0.5 + asn: 64512 + disableMP: false + holdTime: 1m30s + keepaliveTime: 30s + passwordSecret: {} + port: 179 + toAdvertise: + allowed: + mode: filtered + toReceive: + allowed: + mode: filtered + - asn: 64512 + vrf: red + neighbors: + - address: 192.18.0.5 + asn: 64512 + disableMP: false + holdTime: 1m30s + keepaliveTime: 30s + passwordSecret: {} + port: 179 + toAdvertise: + allowed: + mode: filtered + toReceive: + allowed: + mode: filtered +``` + +The admin now creates the following RouteAdvertisements CR: +```yaml +apiVersion: k8s.ovn.org/v1 +kind: RouteAdvertisements +metadata: + name: default +spec: + targetVRF: auto + advertisements: + podNetwork: true + networkSelector: + matchExpressions: + - { key: k8s.ovn.org/metadata.name, operator: In, values: [blue,red] } + nodeSelector: + matchLabels: + kubernetes.io/hostname: ovn-worker +``` + +In the above CR, the targetVRF is set to auto, meaning the advertisements will occur within the VRF corresponding to the +individual networks selected. In this case, the pod subnet for blue will be advertised over the blue VRF, while the pod +subnet for red will be advertised over the red VRF. OVN-Kubernetes creates the following FRRConfiguration: + +```yaml +apiVersion: frrk8s.metallb.io/v1beta1 +kind: FRRConfiguration +metadata: + name: route-advertisements-blue + namespace: metallb-system +spec: + bgp: + routers: + - asn: 64512 + neighbors: + - address: 182.18.0.5 + asn: 64512 + toAdvertise: + allowed: + prefixes: + - 10.0.1.0/24 + vrf: blue + prefixes: + - 10.0.1.0/24 + - asn: 64512 + neighbors: + - address: 192.18.0.5 + asn: 64512 + toAdvertise: + allowed: + prefixes: + - 10.0.1.0/24 + vrf: red + prefixes: + - 10.0.1.0/24 + nodeSelector: + matchLabels: + kubernetes.io/hostname: ovn-worker +``` + +OVN-Kubernetes uses the configuration already in place in FRR and the desired RouteAdvertisements to generate the above +FRRConfiguration. For filtering or choosing what routes to receive, a user should do that in the FRRConfiguration they +declare for peering. + +Note, VRF-Lite is only available when using Local Gateway Mode (routingViaHost: true) in OVN-Kubernetes. + +#### Feature Compatibility + +##### Multiple External Gateways (MEG) + +When using BGP to learn routes to next hops, there can be overlap with gateways detected by the MEG feature. MEG may +still be configured along with BFD in OVN, and overlapping routes learned from BGP will be ignored by OVN-Kubernetes. +BFD may also be configured in FRR, for immediate purging of learned routes by FRR. + +A user can also configure RouteAdvertisements for namespaces affected by MEG. Since MEG directly uses pod IPs +(in disable-snat-multiple-gws mode), the external gateway needs to know where to route pod IPs for ingress and egress +reply traffic. Traditionally this is done by the gateway having its own operator to detect pod subnets via kubernetes +API. With BGP, this is no longer necessary. A user can simply configure RouteAdvertisements, and the pod subnet routes +will be dynamically learned by an external gateway capable of BGP peering. + +##### Egress IP + +EgressIP feature that is dynamically moved between nodes. By enabling the feature in RouteAdvertisements, OVN-Kubernetes +will automatically change FRR-K8S configuration so that the node where an egress IP resides will advertise the IP. This +eliminates the need for nodes to be on the same layer 2 segment, as we no longer have to rely on gratuitous ARP (GARP). + +##### Services + +LoadBalancer and External IP are supported by MetalLB. This feature will handle advertising cluster IPs for services. +Note, the usefulness of advertising ClusterIP may be limited as it will be advertised by multiple nodes (similar to +anycast) and may not work well with stateful connections. + +##### Egress Service + +Full support. + +##### Egress Firewall + +Full support. + +##### Egress QoS + +Full Support. + + +##### Network Policy/ANP + +Full Support. + +##### Direct Pod Ingress + +Direct pod ingress is already enabled for the default cluster network. With direct pod ingress, any external entity can +talk to a pod IP if it sends the packet to the node where the pod lives. Previously, support for direct pod ingress on +user-defined networks was not supported. RouteAdvertisements with this enhancement may select user-defined networks and +enable pod network advertisements. Therefore, it only makes sense to also accept direct pod ingress for these +user-defined networks as well, especially since we know the selected subnets will not overlap in IP address space. + +###### Ingress via OVS bridge + +Modifications will need to be made so that for packets arriving on br-ex, flows are added to steer the selected pod +subnets to the right OVN GR patch port. Today the flow for the default cluster network looks like this: + +``` +[root@ovn-worker ~]# ovs-ofctl show breth0 +OFPT_FEATURES_REPLY (xid=0x2): dpid:00000242ac120003 +n_tables:254, n_buffers:0 +capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP +actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst + 1(eth0): addr:02:42:ac:12:00:03 + config: 0 + state: 0 + current: 10GB-FD COPPER + speed: 10000 Mbps now, 0 Mbps max + 2(patch-breth0_ov): addr:ca:2c:82:e9:06:42 + config: 0 + state: 0 + speed: 0 Mbps now, 0 Mbps max + + +[root@ovn-worker ~]# ovs-ofctl dump-flows breth0 |grep 10.244 + cookie=0xdeff105, duration=437.393s, table=0, n_packets=4, n_bytes=392, idle_age=228, priority=109,ip,in_port=2,dl_src=02:42:ac:12:00:03,nw_src=10.244.1.0/24 actions=ct(commit,zone=64000,exec(load:0x1->NXM_NX_CT_MARK[])),output:1 + cookie=0xdeff105, duration=437.393s, table=0, n_packets=0, n_bytes=0, idle_age=437, priority=104,ip,in_port=2,nw_src=10.244.0.0/16 actions=drop + cookie=0xdeff105, duration=437.393s, table=1, n_packets=4, n_bytes=392, idle_age=228, priority=15,ip,nw_dst=10.244.0.0/16 actions=output:2 + +``` + +Packets matching the pod IP are forwarded directly to OVN, where they are forwarded to the pod without SNAT. Additional +flows will need to be created for additional networks. For shared gateway mode, the reply packet will always return via +OVS and follow a symmetrical path. This is also true if local gateway mode is being used in combination with Multiple +External Gateways (MEG). However, if local gateway mode is used without MEG, then the reply packet will be forwarded into +the kernel networking stack, where it will routed out br-ex via the kernel routing table. + +###### Ingress via a Secondary NIC + +If packets enter into the host via a NIC that is not attached to OVS, the kernel networking stack will forward it into +the proper VRF, where it will be forwarded via ovn-k8s-mp0 of the respective user-defined network. Today when these +packets ingress ovn-k8s-mp0 into OVN, they are SNAT'ed to the ovn-k8s-mp0 address (.2 address). Reasons for this include: +1. To ensure incoming traffic that may be routed to another node via geneve would return back to this node. This is undesirable +and unnecessary for networks where only their respective per-node pod subnet is being advertised to the BGP fabric. +2. If running shared gateway mode, the reply packet would be routed via br-ex with the default gateway configured in +ovn_cluster_router. + +For local gateway mode, changes will need to be made to skip the SNAT as it is not necessary and provides pods with the +true source IP of the sender. + + +Additionally, modifications will need to be made in the kernel routing table to +leak routes to the pod subnets from each user-defined VRF into the default VRF routing table. + +#### Deployment Considerations + +##### MetalLB + +MetalLB is supported today as a day 2 add-on operator. MetalLB supports FRR mode, and has recently added support for +FRR-K8S mode. When the MetalLB Operator deploys MetalLB in FRR-K8S mode, it handles instantiating FRR-K8S. For the purposes +of OVN-Kubernetes integration, we need this as a day 0 function. For pods relying on the underlay and not using an overlay +encapsulation, the BGP routes will need to be learned by the time the pods come up. + +In order to achieve day 0 functionality, FRR-K8S will be launched by CNO as a host networked pod on each node (where +applicable). MetalLB Operator will be modified so that it can launch in FRR-K8S mode, without deploying FRR-K8S, and +integrate with the one launched by CNO. + +This means, there will be two ways of operating: +- The current behaviour, which is: CNO does not deploy FRR-K8s, the MetalLB Operator deploys both MetalLB and FRR-K8s +- CNO deploys FRR-K8s and MetalLB leverages the FRR-K8s instance deployed by CNO + +###### MetalLB deploys FRR-K8s +This is the behaviour implemented in 4.16 as Tech Preview and planned to be GA in 4.17. The users don't care about pod +to pod reachability with BGP, they want to use MetalLB and possibly FRR-K8s for learning routes on the nodes. +The MetalLB operator will deploy FRR-K8s and MetalLB in the same namespace. + +###### CNO deploys FRR-K8s +In this version, CNO deploys FRR-K8s in a separate namespace, so it can be used for the extra features described in this +proposal. The user will need to set: + +- A flag on the CNO configuration, to deploy FRR-K8s and to instruct OVN-K of the presence of the FRR controller +- A deployment mode "FRR-K8s already present" in the "MetalLB" resource, to instruct the operator to deploy MetalLB in +FRR-K8s mode but without deploying FRR-K8s +- In this scenario the permissions given to MetalLB over the FRR-K8s resources must be changed from namespace scoped to +cluster scoped. + +## Handling configuration errors +Because of this dual way of deploying, we must be careful in handling the scenario where a user mistakenly deployed +FRR-K8s both from the MetalLB Operator and from CNO. In this scenario, the FRR-K8s instance of CNO must take precedence +and the MetalLB Operator must produce an error as soon as it sees the extra FRR-K8s instance, and possibly un-deploy +the MetalLB pods, so it's clear some exceptional scenario is happening. + +##### Bare Metal + +Bare Metal deployments expose a virtual IP (VIP) using keepalived. This VIP is moved between control-plane nodes, and +the implementation assumes the master nodes are on the same layer 2 network. With BGP integration, this may no longer be +the case. Therefore, we may need changes to keepalived scripts in order to add FRR configuration for routes to the VIP +when the VIP goes up/down on a node, so that the VIP is announced correctly over the BGP network. + +## Test Plan + +* E2E upstream with a framework (potentially [containerlab.dev](containerlab.dev) to simulate a routed spine and leaf +topology with integration using OVN Kubernetes. +* Testing using transport none for some networks, and Geneve for non-BGP enabled networks. +* Downstream testing to cover BGP functionality including MEG, Egress IP, Egress QoS, etc. +* Scale testing to determine impact of FRR-K8S footprint on large scale deployments. + +## Graduation Criteria + +### Dev Preview -> Tech Preview + +There will be no dev or tech preview for this feature. + +### Tech Preview -> GA + +Targeting GA in OCP version 4.17. + +### Removing a deprecated feature + +N/A + +## Upgrade / Downgrade Strategy + +This feature should have no impact on upgrades. BGP configuration may be configured or removed at any time and previous +routing behavior within the OVN fabric should be restored. For limiting outage on upgrade of FRR-K8S, we may need to use +BGP features like graceful restart. + +## Version Skew Strategy + +N/A + +## Operational Aspects of API Extensions + +Using BGP, especially for east/west transport relies on the user's BGP network. Therefore, BGP control plane outages in +a user's network may impact OpenShift cluster networking. Furthermore, when changing a network's transport there will +be some amount of traffic disruption. Finally, this entire feature will depend on correct BGP peering via FRR-K8S +configuration, as well as settings to match the proper communities, route filtering, and other BGP configuration +within the provider's BGP network. + +## Support Procedures + +## Alternatives diff --git a/enhancements/network/images/bgp_novpn_advertisements.png b/enhancements/network/images/bgp_novpn_advertisements.png new file mode 100644 index 0000000000000000000000000000000000000000..8f4ce50ce02deb62afd088a4d0bce65ca4d77747 GIT binary patch literal 66996 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 literal 0 HcmV?d00001 diff --git a/enhancements/network/images/vrf-lite.png b/enhancements/network/images/vrf-lite.png new file mode 100644 index 0000000000000000000000000000000000000000..bfb26d0ec810e019d8c6c4adb86aeb3f4e7f76cb GIT binary patch literal 77212 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 Date: Mon, 17 Jun 2024 17:08:23 -0400 Subject: [PATCH 2/6] updates Signed-off-by: Tim Rozet --- enhancements/network/bgp-ovn-kubernetes.md | 84 +++++++++++----------- 1 file changed, 43 insertions(+), 41 deletions(-) diff --git a/enhancements/network/bgp-ovn-kubernetes.md b/enhancements/network/bgp-ovn-kubernetes.md index ea67b2699d..01f0bb2b08 100644 --- a/enhancements/network/bgp-ovn-kubernetes.md +++ b/enhancements/network/bgp-ovn-kubernetes.md @@ -113,6 +113,7 @@ advertises VPN routes via BGP sessions over said VRFs. ### Future Goals * Support EVPN configuration and integration with a user’s DC fabric, along with MAC-VRFs and IP-VRFs. +* Support iBGP with route reflectors. ## Proposal @@ -134,7 +135,7 @@ networks for their namespace, but requires admin permission in order to expose t fabric. A typical workflow will be for a user or admin to create a user-defined network, and then the admin will be responsible to: -1. If setting up VRF-Lite, do any host modifications necessary via NMState to enslave a physical interface to the +1. If setting up VRF-Lite, do any host modifications necessary via NMState to enslave an IP interface to the matching network VRF. 2. Configure BGP peering via interacting with the FRR-K8S API for a given set of worker nodes. Also define filters for what routes should be received from the provider network. @@ -189,9 +190,10 @@ a dynamic routing protocol. #### BGP Peering FRR-K8S shall support both internal BGP (iBGP) and external BGP (eBGP). With iBGP, a full mesh topology is required. This -can be cumbersome and have issues with scaling in large clusters. Therefore, FRR-K8S shall also support designating one -or more nodes as route reflectors. With route reflectors, nodes only have to connect to the route reflectors and do not -have to maintain a full mesh with all other nodes in the cluster. +can be cumbersome and have issues with scaling in large clusters. In the future, FRR-K8S shall also support designating one +or more nodes as route reflectors (https://issues.redhat.com/browse/CNF-10719). With route reflectors, nodes only have +to connect to the route reflectors and do not have to maintain a full mesh with all other nodes in the cluster. Therefore, +support for iBGP in this enhancement will be restricted to full mesh only. #### FRR-K8S Integration @@ -232,11 +234,13 @@ metadata: spec: # networkSelector: # nodeSelector: + # frrConfigurationSelector: targetVRF: default advertisements: podNetwork: true egressIP: true clusterIPs: true + externalIPs: true ``` In the above example, an optional networkSelector may also be optionally supplied which will match namespaces/networks. @@ -248,14 +252,26 @@ A networkSelector may select more than one network, including user-defined netwo will be checked by OVN-Kubernetes to determine if there is any overlap of the IP subnets. If so, an error status will be reported to the CRD and no BGP configuration will be done by OVN-Kubernetes. -The CRD will support enabling advertisements for pod subnet, egress IPs, as well as cluster IPs for services on the -selected networks. Note, MetalLB only handles advertising LoadBalancer IP and External IP so there is no conflict of -responsibilities here. - -The "targetVRF" key is used to determine which VRF the routes should be advertised in. The default value is "default", -which indicates the routes from the selected network should be advertised in the default VRF. Alternatively, the user -may specify the value "auto", in which case OVN-Kubernetes will advertise routes in the VRF that corresponds to the -selected network. +The CRD will support enabling advertisements for pod subnet, egress IPs, as well as cluster IPs and external IPs for +services on the selected networks. Note, MetalLB only handles advertising LoadBalancer IP so there is no conflict of +responsibilities here. When the pod network is set to be advertised, there is no longer a need to SNAT pod IPs for this +network to the node IP. Therefore when pod network advertisements are enabled, the traffic from these pods will no longer +be SNAT'ed on egress. + +The "targetVRF" key is used to determine which VRF the routes should be advertised in. The default value is "auto", in +which case OVN-Kubernetes will advertise routes in the VRF that corresponds to the selected network. Alternatively, the +user may specify the name of the VRF, which would cause routes to be leaked for this network onto that VRF. One use case +for this would be when a user wants to define a network with a specific IP addressing scheme, and then wants to advertise +the pod IPs into the provider BGP network without VPN. By specifying the targetVRF as "default", routes will be leaked +into the default VRF. Note that by using route leaking with a user-defined network, the network is no longer fully +isolated, as now any other networks also leaked or attached to that VRF may reach this user-defined network. If a user +attempts to leak routes into a targetVRF for a user-defined network whose IP subnet would collide with another, +OVN-Kubernetes will report an error to the RouteAdvertisement status. + +The frrConfigurationSelector is used in order to determine which FRRConfiguration CR to use for building the OVN-Kubernetes +driven FRRConfiguration. OVN-Kubernetes needs to leverage a pre-existing FRRConfiguration to be able to find required +pieces of configuration like BGP peering, etc. If more than one FRRConfiguration is found matching the selector, then +an error will be propagated to the RouteAdvertisements CR and no configuration shall be done. ##### No Tunnel/Overlay Mode @@ -284,6 +300,8 @@ metadata: namespace: metallb-system resourceVersion: "1323" uid: 99b64be3-4f36-4e0b-8704-75aa5182d89f + labels: + routeAdvertisements: default spec: bgp: routers: @@ -329,8 +347,11 @@ spec: matchLabels: k8s.ovn.org/metadata.name: blue nodeSelector: - matchLabels: + matchLabels: kubernetes.io/hostname: ovn-worker + frrConfigurationSelector: + matchLabels: + routeAdvertisements: default ``` OVNKube-Controller will now see it needs to generate corresponding FRRConfiguration: @@ -391,6 +412,8 @@ kind: FRRConfiguration metadata: name: vpn-ovn-worker namespace: metallb-system + labels: + routeAdvertisements: vpn-blue-red spec: bgp: routers: @@ -442,8 +465,11 @@ spec: matchExpressions: - { key: k8s.ovn.org/metadata.name, operator: In, values: [blue,red] } nodeSelector: - matchLabels: + matchLabels: kubernetes.io/hostname: ovn-worker + frrConfigurationSelector: + matchLabels: + routeAdvertisements: vpn-blue-red ``` In the above CR, the targetVRF is set to auto, meaning the advertisements will occur within the VRF corresponding to the @@ -605,33 +631,9 @@ of OVN-Kubernetes integration, we need this as a day 0 function. For pods relyin encapsulation, the BGP routes will need to be learned by the time the pods come up. In order to achieve day 0 functionality, FRR-K8S will be launched by CNO as a host networked pod on each node (where -applicable). MetalLB Operator will be modified so that it can launch in FRR-K8S mode, without deploying FRR-K8S, and -integrate with the one launched by CNO. - -This means, there will be two ways of operating: -- The current behaviour, which is: CNO does not deploy FRR-K8s, the MetalLB Operator deploys both MetalLB and FRR-K8s -- CNO deploys FRR-K8s and MetalLB leverages the FRR-K8s instance deployed by CNO - -###### MetalLB deploys FRR-K8s -This is the behaviour implemented in 4.16 as Tech Preview and planned to be GA in 4.17. The users don't care about pod -to pod reachability with BGP, they want to use MetalLB and possibly FRR-K8s for learning routes on the nodes. -The MetalLB operator will deploy FRR-K8s and MetalLB in the same namespace. - -###### CNO deploys FRR-K8s -In this version, CNO deploys FRR-K8s in a separate namespace, so it can be used for the extra features described in this -proposal. The user will need to set: - -- A flag on the CNO configuration, to deploy FRR-K8s and to instruct OVN-K of the presence of the FRR controller -- A deployment mode "FRR-K8s already present" in the "MetalLB" resource, to instruct the operator to deploy MetalLB in -FRR-K8s mode but without deploying FRR-K8s -- In this scenario the permissions given to MetalLB over the FRR-K8s resources must be changed from namespace scoped to -cluster scoped. - -## Handling configuration errors -Because of this dual way of deploying, we must be careful in handling the scenario where a user mistakenly deployed -FRR-K8s both from the MetalLB Operator and from CNO. In this scenario, the FRR-K8s instance of CNO must take precedence -and the MetalLB Operator must produce an error as soon as it sees the extra FRR-K8s instance, and possibly un-deploy -the MetalLB pods, so it's clear some exceptional scenario is happening. +applicable) via a new OpenShift API. MetalLB Operator will be modified so that it can launch in FRR-K8S mode, and will +directly write to the API to signal that CNO should deploy FRR-K8S. CNO will deploy FRR-K8s in a separate namespace, and +MetalLB RBAC will be updated so that it may write and have access to resources in the FRR-K8S namespace. ##### Bare Metal From 60a5e4bc100d4941c9d0497474ed9c24a5aef837 Mon Sep 17 00:00:00 2001 From: Tim Rozet Date: Thu, 20 Jun 2024 18:10:09 -0400 Subject: [PATCH 3/6] Clarify rawConfig in example Signed-off-by: Tim Rozet --- enhancements/network/bgp-ovn-kubernetes.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/enhancements/network/bgp-ovn-kubernetes.md b/enhancements/network/bgp-ovn-kubernetes.md index 01f0bb2b08..2f5cb496aa 100644 --- a/enhancements/network/bgp-ovn-kubernetes.md +++ b/enhancements/network/bgp-ovn-kubernetes.md @@ -395,7 +395,9 @@ spec: In the above configuration generated by OVN-Kubernetes, the subnet 10.0.1.0/24 which belongs to VRF blue, is being imported into the default VRF, and advertised to the 172.18.0.5 neighbor. This is because the targetVRF was defaulted so the routes are leaked and advertised in the default VRF. Additionally, routes are being imported from the default VRF -into the blue VRF. +into the blue VRF. At the time of this writing, FRR-K8S does not support importing vrf routes as an API, and thus rawConfig +is used. However, when implementing this enhancement every attempt should be made to add support into FRR-K8S to use its +API rather than using rawConfig. ##### Example 2: VRF Lite - Advertising pod IPs from a user-defined network over BGP with VPN From 92c8551be9705afdc301c6f6cf30eac339db2a99 Mon Sep 17 00:00:00 2001 From: Tim Rozet Date: Wed, 26 Jun 2024 18:22:09 -0400 Subject: [PATCH 4/6] Addresses review comments Changes-Include: - Removal of support for advertising KAPI VIP - Removal of support for advertising service cluster IP/external IP - OpenShift API added Signed-off-by: Tim Rozet --- enhancements/network/bgp-ovn-kubernetes.md | 44 ++++++++++++++-------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/enhancements/network/bgp-ovn-kubernetes.md b/enhancements/network/bgp-ovn-kubernetes.md index 2f5cb496aa..b5e2911cb2 100644 --- a/enhancements/network/bgp-ovn-kubernetes.md +++ b/enhancements/network/bgp-ovn-kubernetes.md @@ -114,6 +114,7 @@ advertises VPN routes via BGP sessions over said VRFs. * Support EVPN configuration and integration with a user’s DC fabric, along with MAC-VRFs and IP-VRFs. * Support iBGP with route reflectors. +* Potentially advertising other IP addresses, including the Kubernetes API VIP across the BGP fabric. ## Proposal @@ -149,7 +150,8 @@ For detailed examples, see the [BGP Configuration](#bgp-configuration) section. FRR-K8S API will be used in order to create BGP Peering and configure other BGP related configuration. A RouteAdvertisements CRD will be introduced in order to determine which routes should be advertised for specific networks. Additionally, the network CRD will be modified in order to expose a new transport field to determine if encapsulation -should be used for east/west traffic. +should be used for east/west traffic. Finally, the OpenShift API itself will be modified to expose a setting so that +Cluster Network Operator (CNO) can deploy FRR and FRR-K8S. ### Topology Considerations @@ -220,6 +222,23 @@ will happen irrespective of gateway mode, as some features in local gateway mode #### API Changes +##### OpenShift API + +The OpenShift API will be modified in order to allow CNO to deploy FRR and FRR-K8S CRDs: + +```golang +// NetworkSpec is the top-level network configuration object. +type NetworkSpec struct { + // ... + // deployFRR specifies whether or not the Free Range Routing (FRR) stack + // along with FRR-K8S API should be deployed by the operator. + // FRR is required for enabling for using any OpenShift features that require dynamic + // routing. This includes BGP support for OVN-Kubernetes and MetalLB. + // +optional + DeployFRR *bool `json:"deployFRR,omitempty"` +} +``` + ##### Route Advertisements When OVN-Kubernetes detects that a FRR-K8S CR has been created for BGP peering, OVN-Kubernetes will by default @@ -239,8 +258,6 @@ spec: advertisements: podNetwork: true egressIP: true - clusterIPs: true - externalIPs: true ``` In the above example, an optional networkSelector may also be optionally supplied which will match namespaces/networks. @@ -252,11 +269,10 @@ A networkSelector may select more than one network, including user-defined netwo will be checked by OVN-Kubernetes to determine if there is any overlap of the IP subnets. If so, an error status will be reported to the CRD and no BGP configuration will be done by OVN-Kubernetes. -The CRD will support enabling advertisements for pod subnet, egress IPs, as well as cluster IPs and external IPs for -services on the selected networks. Note, MetalLB only handles advertising LoadBalancer IP so there is no conflict of -responsibilities here. When the pod network is set to be advertised, there is no longer a need to SNAT pod IPs for this -network to the node IP. Therefore when pod network advertisements are enabled, the traffic from these pods will no longer -be SNAT'ed on egress. +The CRD will support enabling advertisements for pod subnet and egress IPs. Note, MetalLB still handles advertising +LoadBalancer IP so there is no conflict of responsibilities here. When the pod network is set to be advertised, there is +no longer a need to SNAT pod IPs for this network to the node IP. Therefore, when pod network advertisements are enabled, +the traffic from these pods will no longer be SNAT'ed on egress. The "targetVRF" key is used to determine which VRF the routes should be advertised in. The default value is "auto", in which case OVN-Kubernetes will advertise routes in the VRF that corresponds to the selected network. Alternatively, the @@ -542,9 +558,7 @@ eliminates the need for nodes to be on the same layer 2 segment, as we no longer ##### Services -LoadBalancer and External IP are supported by MetalLB. This feature will handle advertising cluster IPs for services. -Note, the usefulness of advertising ClusterIP may be limited as it will be advertised by multiple nodes (similar to -anycast) and may not work well with stateful connections. +MetalLB will still be used in order to advertise services across the BGP fabric. ##### Egress Service @@ -637,12 +651,10 @@ applicable) via a new OpenShift API. MetalLB Operator will be modified so that i directly write to the API to signal that CNO should deploy FRR-K8S. CNO will deploy FRR-K8s in a separate namespace, and MetalLB RBAC will be updated so that it may write and have access to resources in the FRR-K8S namespace. -##### Bare Metal +This deployment methodology will solve the following use cases: -Bare Metal deployments expose a virtual IP (VIP) using keepalived. This VIP is moved between control-plane nodes, and -the implementation assumes the master nodes are on the same layer 2 network. With BGP integration, this may no longer be -the case. Therefore, we may need changes to keepalived scripts in order to add FRR configuration for routes to the VIP -when the VIP goes up/down on a node, so that the VIP is announced correctly over the BGP network. +1. The user needs BGP from node start up to serve pods by the time OVN-Kubernetes and pods are brought up by kubelet. +2. The user does not care about BGP in OVN-Kubernetes, and simply wants to use MetalLB as a day 2 operation. ## Test Plan From 0daad1c3668188fdb57380dacd5d43bc8ad8c890 Mon Sep 17 00:00:00 2001 From: Tim Rozet Date: Thu, 11 Jul 2024 20:44:58 -0400 Subject: [PATCH 5/6] Addresses upgrade, API, and other comments Signed-off-by: Tim Rozet --- enhancements/network/bgp-ovn-kubernetes.md | 123 ++++++++++++++++----- 1 file changed, 98 insertions(+), 25 deletions(-) diff --git a/enhancements/network/bgp-ovn-kubernetes.md b/enhancements/network/bgp-ovn-kubernetes.md index b5e2911cb2..b3196dadf3 100644 --- a/enhancements/network/bgp-ovn-kubernetes.md +++ b/enhancements/network/bgp-ovn-kubernetes.md @@ -41,8 +41,8 @@ external, physical network of the cluster which a user administers will be calle ### Importing Routes from the Provider Network Today in OpenShift there is no API for a user to be able to configure routes into OVN. In order for a user to change how -cluster traffic is routed egress into the cluster, the user leverages local gateway mode, which forces egress traffic to -hop through the Linux host networking stack. There a user can configure routes inside the host via NM State. This +egress traffic is routed, the user leverages local gateway mode. This mode forces traffic to hop through the Linux +networking stack, and there a user can configure routes inside of the host via NM State to control egress routing. This manual configuration would need to be performed and maintained across nodes and VRFs within each node. Additionally, if a user chooses to not manage routes within the host for local gateway mode, or the user chooses shared @@ -76,7 +76,11 @@ and thus reducing the overhead and byte size of each packet. This allows for gre ### Multi-homing, Link Redundancy, Fast Convergence BGP can use multi-homing with ECMP routing in order to provide layer 3 failover. When a link goes down, BGP can reroute -via a different path. This functionality can be coupled with BFD in order to provide fast failover. +via a different path. This functionality can be coupled with BFD in order to provide fast failover. A typical use case +is in a spine and leaf topology, where a node has multiple NICs for redundancy that connect to different BGP routers in +topology. In this case if a link goes down to one BGP peer or the BGP peer fails, BFD can detect the outage on the order +of milliseconds to hundreds of milliseconds and quickly assist BGP in purging the routes to that failed peer. This then +causes fast failover and route convergence to the alternate peer. ### User Stories @@ -87,8 +91,8 @@ via a different path. This functionality can be coupled with BFD in order to pro advertise egress routes for the Kubernetes pod traffic in either gateway mode. * As a user where maximum throughput is a priority, I want to reduce packet overhead by not having to encapsulate traffic with Geneve. - * As a baremetal or egress IP user, I do not want to have to restrict my nodes to the same layer 2 segment and prefer - to use a pure routing implementation to handle advertising virtual IP (VIP) movement across nodes. + * As an egress IP user, I do not want to have to restrict my nodes to the same layer 2 segment and prefer + to use a pure routing implementation to handle advertising egress IP movement across nodes. ### Goals @@ -119,15 +123,19 @@ advertises VPN routes via BGP sessions over said VRFs. ## Proposal OVN-Kubernetes will leverage other projects that already exist to enable BGP in Linux. FRR will be used as the BGP -speaker and already has EVPN support for native Linux constructs like Linux bridges, VRF devices, VXLAN tunnels, etc. -FRR may need some code contributions to allow it to integrate with OVN and Open vSwitch. For FRR configuration, the +speaker, as well as provide support for other protocols like BFD. For FRR configuration, the MetalLB project has already started an API to be able to configure FRR: [https://github.com/metallb/frr-k8s](https://github.com/metallb/frr-k8s). While some of the configuration support for FRR may be directly exposed by FRR-K8S API, it may also be the case that some intermediary CRD provided by OVN-Kubernetes is required to integrate OVN-Kubernetes networking concepts into FRR. Functionally, FRR will handle advertising and importing routes and configuring those inside a Linux VRF. OVN-Kubernetes -will be responsible for listening on netlink and configuring OVN-Kubernetes logical routers with routes learned by FRR. +will be responsible for listening on netlink and configuring logical routers in OVN with routes learned +by FRR. OVN-Kubernetes will manage FRR configuration through the FRR-K8S API in order to advertise routes outside of the +node onto the provider network. + +There should be no changes required in FRR. FRR-K8S may need extended APIs to cover the OVN-Kubernetes use cases +proposed in this enhancement. OVN will require no changes. ### Workflow Description @@ -197,6 +205,18 @@ or more nodes as route reflectors (https://issues.redhat.com/browse/CNF-10719). to connect to the route reflectors and do not have to maintain a full mesh with all other nodes in the cluster. Therefore, support for iBGP in this enhancement will be restricted to full mesh only. +#### BFD + +Bi-directional Forwarding Detection (BFD) is used to detect link outages within milliseconds. This technology can be +associated with routing in order to signal to a router that a peer has lost connection faster than the routing protocol +can detect it. This assists with purging routes that are no longer viable, and recalculating optimal paths in the +Routing Information Base (RIB). + +In OVN, BFD is supported today with the Multiple External Gateways (MEG) feature. However, there is no support for +OVN to communicate with the FRR stack. Therefore for BFD support with BGP, FRR BFD daemon will be used in order to +detect BFD link failures. It will then signal to FRR that the peer is down, and FRR will remove the routes routes from +its RIB. Upon noticing this via netlink, OVN-Kubernetes will then remove those routes from OVN as well. + #### FRR-K8S Integration As previously mentioned frr-k8s will be used in order to deploy and manage FRR configuration. Support will be added @@ -227,18 +247,51 @@ will happen irrespective of gateway mode, as some features in local gateway mode The OpenShift API will be modified in order to allow CNO to deploy FRR and FRR-K8S CRDs: ```golang +type AdvancedRoutingConfig struct { + // +kubebuilder:validation:Enum="";FRR,Disabled + // +optional + Provider string`json:"provider,omitempty"` +} + // NetworkSpec is the top-level network configuration object. type NetworkSpec struct { // ... - // deployFRR specifies whether or not the Free Range Routing (FRR) stack - // along with FRR-K8S API should be deployed by the operator. + // advancedRouting specifies whether or not advanced routing features + // should be deployed on the cluster. Currently the only acceptable value + // other than Disabled is FRR, which will deploy the Free Range Routing (FRR) stack + // along with FRR-K8S API. // FRR is required for enabling for using any OpenShift features that require dynamic // routing. This includes BGP support for OVN-Kubernetes and MetalLB. // +optional - DeployFRR *bool `json:"deployFRR,omitempty"` + // +kubebuilder:default={"provider": "Disabled"} + // +default={"provider": "Disabled"} + AdvancedRouting *AdvancedRoutingConfig `json:"advancedRouting,omitempty"` +} + +// ovnKubernetesConfig contains the configuration parameters for networks +// using the ovn-kubernetes network project +type OVNKubernetesConfig struct { + // routeAdvertisements determines the capability of advertising cluster + // network routes with BGP. This capability is configured through the + // ovn-kubernetes RouteAdvertisements CRD. Requires global network + // AdvancedRouting to be enabled. Allowed values are "Enabled", "Disabled" + // and ommited. When omitted, this means the user has no opinion and the + // platform is left to choose reasonable defaults. These defaults are + // subject to change over time. The current default is "Disabled". + // +openshift:enable:FeatureGate=BGP + // +kubebuilder:validation:Enum="";Enabled;Disabled + // +optional + RouteAdvertisements string `json:"routeAdvertisements,omitempty"` } ``` +In the above API changes, AdvancedRouting is used in order to signal to CNO to deploy FRR and FRR-K8S, while the RouteAdvertisements +API will enable the route advertisement feature within OVN-Kubernetes. AdvancedRouting may be used without enabling RouteAdvertisements, such +as for MetalLb functionality. However, when enabling RouteAdvertisements it is required to enable FRR as the AdvancedRouting provider. + +Note, at this time there is no support for a nodeSelector to choose which nodes to deploy AdvancedRouting to. In the future this may change, +but for now when enabling a provider, it will be enabled on all nodes. + ##### Route Advertisements When OVN-Kubernetes detects that a FRR-K8S CR has been created for BGP peering, OVN-Kubernetes will by default @@ -269,20 +322,24 @@ A networkSelector may select more than one network, including user-defined netwo will be checked by OVN-Kubernetes to determine if there is any overlap of the IP subnets. If so, an error status will be reported to the CRD and no BGP configuration will be done by OVN-Kubernetes. +Multiple CRs may not select the same network. If this happens OVN-Kubernetes will report an error to the +RouteAdvertisements CR and will refuse to apply the config. + The CRD will support enabling advertisements for pod subnet and egress IPs. Note, MetalLB still handles advertising LoadBalancer IP so there is no conflict of responsibilities here. When the pod network is set to be advertised, there is no longer a need to SNAT pod IPs for this network to the node IP. Therefore, when pod network advertisements are enabled, the traffic from these pods will no longer be SNAT'ed on egress. -The "targetVRF" key is used to determine which VRF the routes should be advertised in. The default value is "auto", in -which case OVN-Kubernetes will advertise routes in the VRF that corresponds to the selected network. Alternatively, the -user may specify the name of the VRF, which would cause routes to be leaked for this network onto that VRF. One use case -for this would be when a user wants to define a network with a specific IP addressing scheme, and then wants to advertise -the pod IPs into the provider BGP network without VPN. By specifying the targetVRF as "default", routes will be leaked -into the default VRF. Note that by using route leaking with a user-defined network, the network is no longer fully +The "targetVRF" key is used to determine which VRF the routes should be advertised in. The default value is "default", in +which case routes will be leaked into the default VRF. One use case for this would be when a user wants to define a +network with a specific IP addressing scheme, and then wants to advertise the pod IPs into the provider BGP network without +VPN. Note that by using route leaking with a user-defined network, the network is no longer fully isolated, as now any other networks also leaked or attached to that VRF may reach this user-defined network. If a user attempts to leak routes into a targetVRF for a user-defined network whose IP subnet would collide with another, -OVN-Kubernetes will report an error to the RouteAdvertisement status. +OVN-Kubernetes will report an error to the RouteAdvertisement status. Alternatively, a user may specify the value "auto", +which in which case OVN-Kubernetes will advertise routes in the VRF that corresponds to the selected network. Any other +values other than "auto" or "default" will result in an error. There is no support at this time for routing leaking into +any other VRF. The frrConfigurationSelector is used in order to determine which FRRConfiguration CR to use for building the OVN-Kubernetes driven FRRConfiguration. OVN-Kubernetes needs to leverage a pre-existing FRRConfiguration to be able to find required @@ -295,10 +352,10 @@ Changes will be made to the network CRD(s) in order to specify the method of tra field, “transport” will be added with values “geneve” or “none” (default geneve). The transport option in the CRD may be used to toggle between using Geneve encapsulation (the default today) or using no encapsulation. With no encapsulation, east/west packets are routed directly on the underlay using routing learned via BGP. This is supported for Layer 3 -networks only. Enabling a transport of “none” for Layer 2 networks will have no effect. Enabling a transport of “none” -without selecting all nodes for RouteAdvertisements will also break east/west traffic between those nodes, as there will -not be routes propagated into the BGP network for unselected nodes. Users should expect disruption when the transport of -a network is changed. +networks only. Enabling a transport of “none” for Layer 2 networks will result in an error status in the network CR. +Enabling a transport of “none” without selecting all nodes for RouteAdvertisements will also break east/west traffic +between those nodes, as there will not be routes propagated into the BGP network for unselected nodes. Users should +expect disruption when the transport of a network is changed. #### BGP Configuration @@ -680,9 +737,25 @@ N/A ## Upgrade / Downgrade Strategy -This feature should have no impact on upgrades. BGP configuration may be configured or removed at any time and previous -routing behavior within the OVN fabric should be restored. For limiting outage on upgrade of FRR-K8S, we may need to use -BGP features like graceful restart. +This feature should have no impact on upgrades for OVN-Kubernetes networking. BGP configuration may be configured or removed at any time and previous +routing behavior within the OVN fabric should be restored. However, there is a significant impact on upgrades for MetalLB. +MetalLB Operator is a day 2 add on. During upgrade the order is: + +1. API upgrades. +2. Day 2 operators upgrade. +3. CNO upgrades. + +During this upgrade any users of MetalLB will be impacted. As the new version of MetalLB rolls out, it is no longer in charge +of running FRR or FRR-K8S. This is now CNO's responsibility. Therefore there could be a gap of time between 2 and 3 where MetalLB +is no longer functioning. Note, today MetalLB upgrade is not without outage. There is no support pre-4.17 for BGP graceful +restart, which means there is always an outage in the dataplane when MetalLB upgrades. However, in order to minimize the impact +of the upgrade with the changes mentioned in this enhancement, modifications will be made to MetalLB. + +When MetalLB operator upgrades it will look for the current version of CNO. It will wait to rollout its new daemonset for +MetalLB until CNO has upgraded to its 4.17 version. At this time it will start rolling out new versions of MetalLB that will +not contain FRR. Meanwhile CNO will be launching FRR on all nodes at once. This minimizes the amount of downtime during the +4.16->4.17 upgrade. Post 4.17 upgrades will not have this problem and to limit additional outage, users should enable BGP +graceful restart. ## Version Skew Strategy From a52ba131cadf129bc59d86d3a25bb8a58f8992de Mon Sep 17 00:00:00 2001 From: Tim Rozet Date: Mon, 5 Aug 2024 10:38:57 -0400 Subject: [PATCH 6/6] Update API and address one minor comment Signed-off-by: Tim Rozet --- enhancements/network/bgp-ovn-kubernetes.md | 83 +++++++++++++++------- 1 file changed, 58 insertions(+), 25 deletions(-) diff --git a/enhancements/network/bgp-ovn-kubernetes.md b/enhancements/network/bgp-ovn-kubernetes.md index b3196dadf3..c7f941a57e 100644 --- a/enhancements/network/bgp-ovn-kubernetes.md +++ b/enhancements/network/bgp-ovn-kubernetes.md @@ -214,8 +214,9 @@ Routing Information Base (RIB). In OVN, BFD is supported today with the Multiple External Gateways (MEG) feature. However, there is no support for OVN to communicate with the FRR stack. Therefore for BFD support with BGP, FRR BFD daemon will be used in order to -detect BFD link failures. It will then signal to FRR that the peer is down, and FRR will remove the routes routes from -its RIB. Upon noticing this via netlink, OVN-Kubernetes will then remove those routes from OVN as well. +detect BFD link failures. It will then signal to FRR that the peer is down, and FRR will remove the routes from +its RIB. Upon noticing this via netlink, OVN-Kubernetes will then remove those routes from OVN as well. Additionally, +the external peer will remove its routes that were advertised by this OVNK/FRR-K8s node. #### FRR-K8S Integration @@ -247,41 +248,73 @@ will happen irrespective of gateway mode, as some features in local gateway mode The OpenShift API will be modified in order to allow CNO to deploy FRR and FRR-K8S CRDs: ```golang -type AdvancedRoutingConfig struct { - // +kubebuilder:validation:Enum="";FRR,Disabled - // +optional - Provider string`json:"provider,omitempty"` +// RoutingCapabilitiesProvider is a component providing routing capabilities. +// +kubebuilder:validation:Enum=FRR +type RoutingCapabilitiesProvider string + +const ( + // RoutingCapabilitiesProviderFRR determines FRR is providing advanced + // routing capabilities. + RoutingCapabilitiesProviderFRR RoutingCapabilitiesProvider = "FRR" +) + +// AdditionalRoutingCapabilities describes components and relevant configuration providing +// advanced routing capabilities. +type AdditionalRoutingCapabilities struct { + // providers is a set of enabled components that provide additional routing + // capabilities. Entries on this list must be unique. The only valid value + // is currrently "FRR" which provides FRR routing capabilities through the + // deployment of FRR. + // +listType=atomic + // +kubebuilder:validation:Required + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:validation:MaxItems=1 + // +kubebuilder:validation:XValidation:rule="self.all(x, self.exists_one(y, x == y))" + Providers []RoutingCapabilitiesProvider `json:"providers"` } // NetworkSpec is the top-level network configuration object. type NetworkSpec struct { // ... - // advancedRouting specifies whether or not advanced routing features - // should be deployed on the cluster. Currently the only acceptable value - // other than Disabled is FRR, which will deploy the Free Range Routing (FRR) stack - // along with FRR-K8S API. - // FRR is required for enabling for using any OpenShift features that require dynamic - // routing. This includes BGP support for OVN-Kubernetes and MetalLB. + // additionalRoutingCapabilities describes components and relevant + // configuration providing additional routing capabilities. When set, it + // enables such components and the usage of the routing capabilities they + // provide for the machine network. Upstream operators, like MetalLB + // operator, requiring these capabilities may rely on, or automatically set + // this attribute. Network plugins may leverage advanced routing + // capabilities acquired through the enablement of these components but may + // require specific configuration on their side to do so; refer to their + // respective documentation and configuration options. + // +openshift:enable:FeatureGate=AdditionalRoutingCapabilities // +optional - // +kubebuilder:default={"provider": "Disabled"} - // +default={"provider": "Disabled"} - AdvancedRouting *AdvancedRoutingConfig `json:"advancedRouting,omitempty"` + AdditionalRoutingCapabilities *AdditionalRoutingCapabilities `json:"additionalRoutingCapabilities,omitempty"` } +// +kubebuilder:validation:Enum:="";"Enabled";"Disabled" +type RouteAdvertisementsEnablement string + +var ( + // RouteAdvertisementsEnabled enables route advertisements for ovn-kubernetes + RouteAdvertisementsEnabled RouteAdvertisementsEnablement = "Enabled" + // RouteAdvertisementsDisabled disables route advertisements for ovn-kubernetes + RouteAdvertisementsDisabled RouteAdvertisementsEnablement = "Disabled" +) + // ovnKubernetesConfig contains the configuration parameters for networks // using the ovn-kubernetes network project type OVNKubernetesConfig struct { - // routeAdvertisements determines the capability of advertising cluster - // network routes with BGP. This capability is configured through the - // ovn-kubernetes RouteAdvertisements CRD. Requires global network - // AdvancedRouting to be enabled. Allowed values are "Enabled", "Disabled" - // and ommited. When omitted, this means the user has no opinion and the - // platform is left to choose reasonable defaults. These defaults are - // subject to change over time. The current default is "Disabled". - // +openshift:enable:FeatureGate=BGP - // +kubebuilder:validation:Enum="";Enabled;Disabled + // routeAdvertisements determines if the functionality to advertise cluster + // network routes through a dynamic routing protocol, such as BGP, is + // enabled or not. This functionality is configured through the + // ovn-kubernetes RouteAdvertisements CRD. Requires the 'FRR' routing + // capability provider to be enabled as an additional routing capability. + // Allowed values are "Enabled", "Disabled" and ommited. When omitted, this + // means the user has no opinion and the platform is left to choose + // reasonable defaults. These defaults are subject to change over time. The + // current default is "Disabled". + // +openshift:enable:FeatureGate=RouteAdvertisements // +optional - RouteAdvertisements string `json:"routeAdvertisements,omitempty"` + RouteAdvertisements RouteAdvertisementsEnablement `json:"routeAdvertisements,omitempty"` } ```