End-to-end scenarios — ovn-bgp-agent — branch stable/2026.2
Branch
stable/2026.2@f770768b41dc(7.0.0-2-gf770768) — repository https://opendev.org/openstack/ovn-bgp-agent — analysed on 2026-10-28
Participants: Neutron (neutron-server with the OVN mechanism driver, writes the NB), NB/SB (OVN databases), ovn-controller (binds ports, writes SB), Agent (ovn-bgp-agent on the node), Kernel (netlink, through privsep), OVS (ovs-vsctl/ovs-ofctl), FRR (bgpd/zebra), Fabric (BGP peers). The exact commands of each step are in 03-interactions and, as recorded data, in _rewrite/side-effects_stable-2026.2.json.
1. Agent start and steady state
Context: a node starts the agent with the default SB driver and underlay.
sequenceDiagram
autonumber
participant AG as Agent
participant OVSDB as Local OVSDB
participant SB as OVN SB
participant K as Kernel
participant OVS as OVS (ofctl)
participant FRR as FRR
AG->>OVSDB: monitor Open_vSwitch (system-id, ovn-remote, ovn-bridge-mappings)
AG->>K: ensure VRF bgp-vrf (table 10), dummy bgp-nic in the VRF
AG->>FRR: vtysh -f (router bgp AS: import vrf bgp-vrf; router bgp AS vrf bgp-vrf: redistribute connected)
AG->>SB: monitor_cond (Port_Binding, Load_Balancer, Chassis_Private name==system-id, …)
SB-->>AG: initial rows (ChassisPrivateCreateEvent: first_time only)
loop every reconcile_interval (300 s), first run at start
AG->>K: rt_tables entry + default routes per bridge, 169.254.x.y / fd53:… on bridges, proxy_arp/ndp
AG->>OVS: dump-flows cookie=999, add MAC-tweak flows, delete extra ones
AG->>SB: (local cache) ports bound here, cr-lrps here, patch ports, LBs
AG->>K: ip rule / ip route / ip addr on bgp-nic for every expected IP
AG->>K: delete leftover IPs, rules, routes, VLAN devices
end
loop every frr_reconcile_interval (15 s)
AG->>K: ensure bgp-vrf and bgp-nic
AG->>FRR: vtysh -f (same VRF-leak fragment)
endDiagnostics: nothing announced at all → check the log for Unknown router-id, needed for route leaking (FRR has no router-id and bgp_router_id is unset, ovn_bgp_agent/drivers/openstack/utils/frr.py:182-186); ip addr show bgp-nic lists what the agent believes it exposes; ip rule and ip route show table <bridge> show the ingress wiring; ovs-ofctl dump-flows br-ex cookie=999/-1 the egress flow. A sync error (Unexpected exception while running the sync) skips the cleanup phase.
2. VM booted on a provider network (NB driver, underlay)
Context: driver = nb_ovn_bgp_driver, exposing_method = underlay; network public is mapped to br-ex on the compute node. This is the intended flow; on this branch defect D16 makes the wiring step fail with KeyError: 'br-ex' (logged Unexpected exception while wiring provider port), so the IP is not announced (02 § 4).
sequenceDiagram
autonumber
participant N as Neutron
participant NB as OVN NB
participant OC as ovn-controller
participant AG as Agent (compute)
participant K as Kernel
participant OVS as OVS
participant FRR as FRR
participant F as Fabric
N->>NB: LSP add (addresses "mac ip", requested-chassis=compute, neutron:network_name)
OC->>NB: (via northd/SB) LSP up=true after binding
NB-->>AG: update LSP up false→true
Note over AG: LogicalSwitchPortProviderCreateEvent matches: bound here, up, provider switch, not yet exposed
AG->>NB: (local cache) localnet port of the switch → network_name, tag
AG->>K: ip rule to IP/32 table br-ex; ip route IP dev br-ex[.vlan] table br-ex
AG->>OVS: get Interface patch-provnet-…-to-br-int ofport; add MAC-tweak flow if missing
alt patch port not yet created on this node
OVS-->>AG: ofport [] for 5 s → PortNotFound
Note over AG: logged "Unexpected exception while wiring provider port"; IP not announced until next sync (defect D1)
else
AG->>K: ip addr add IP/32 dev bgp-nic
K->>FRR: zebra: connected route in vrf bgp-vrf
FRR->>F: BGP UPDATE IP/32 (leaked into the default instance)
endDiagnostics: if step 5 is never reached, check that requested-chassis equals the OVS external_ids:hostname of the node (ovn_bgp_agent/drivers/openstack/utils/ovs.py:296-305), and that the switch has a localnet port whose network_name is in ovn-bridge-mappings. VM deleted → LogicalSwitchPortProviderDeleteEvent: ip addr del first (BGP withdraw), then rule and route.
3. Floating IP association, centralized (SB driver)
Context: default SB driver; router r1 has its gateway (cr-lrp) on network node net1; a VM on a tenant network behind r1 runs on compute cmp1. With the SB driver, the FIP is announced by the node of the cr-lrp when the FIP's nat_addresses entry is resident there.
sequenceDiagram
autonumber
participant N as Neutron
participant SB as OVN SB
participant AG as Agent (net1)
participant K as Kernel (net1)
participant FRR as FRR (net1)
N->>SB: (via NB/northd) patch port nat_addresses += "mac FIP is_chassis_resident(\"cr-lrp-X\")"
SB-->>AG: Port_Binding update (patch, chassis empty, nat_addresses changed)
Note over AG: FIPSetEvent: IPs new for cr-lrp-X
AG->>SB: (cache) cr-lrp-X bound to net1? patch datapath has a localnet?
alt cr-lrp-X on this node and provider network
AG->>K: ip rule to FIP/32 table br-ex; ip route FIP dev br-ex table br-ex
AG->>K: ip addr add FIP/32 dev bgp-nic
K->>FRR: connected route → BGP UPDATE FIP/32
else gateway elsewhere
Note over AG: nothing; the node hosting cr-lrp-X does it
endDiagnostics: FIP not reachable → on the node that hosts cr-lrp-X (ovn-sbctl find Port_Binding logical_port=cr-lrp-X), check bgp-nic. If the gateway fails over, the old node withdraws on PortBindingChassisDeletedEvent of the cr-lrp (which also withdraws its FIPs, subnets and LBs) and the new node exposes on PortBindingChassisCreatedEvent.
4. Router gateway failover with tenant networks (NB driver, expose_tenant_networks, subnet method)
sequenceDiagram
autonumber
participant SB as OVN (northd/controller)
participant NB as OVN NB
participant A1 as Agent (old gateway node)
participant A2 as Agent (new gateway node)
participant K2 as Kernel (new)
participant F as Fabric
SB->>NB: LRP lrp-gw status:hosting-chassis = node2
NB-->>A1: LRP update (hosting-chassis node1 → node2)
Note over A1: ChassisRedirectDeleteEvent
A1->>A1: withdraw subnets (unwire rules/routes, delete table-10 subnet routes), LBs, gateway IP
NB-->>A2: LRP update (… → node2)
Note over A2: ChassisRedirectCreateEvent
A2->>K2: rule + route GW_IP table br-ex; ip neigh GW_IP lladdr ROUTER_MAC permanent; ip addr GW_IP/32 dev bgp-nic
A2->>NB: (cache) router-interface LSPs of the router (up, device_owner=network:router_interface)
loop each subnet CIDR (SNAT/addr-scope filters)
A2->>K2: ip rule to CIDR table br-ex; ip route CIDR via GW_IP dev br-ex table br-ex
A2->>K2: ip route CIDR via GW_IP dev bgp-nic table 10
end
K2->>F: FRR (redistribute kernel) BGP UPDATE CIDR, GW_IP/32
A2->>A2: expose LB VIPs / VIP-FIPs / PF FIPs of the routerDiagnostics: tenant prefix missing on the new node → check require_snat_disabled_for_tenant_networks (INFO All ips (%s) were removed due to SNAT requirement…), address_scopes (DEBUG Not exposing subnet CIDR's), and the OVN version (WARNING OVN version does not include support for status information). Between the two events both or neither node may announce for a short time; the fabric converges on BGP UPDATE/WITHDRAW.
5. Live migration of a VM with a distributed FIP (NB driver)
Context: neutron:fip-distributed = True; VM with FIP moves from cmp1 to cmp2. The sequence of NB updates is documented in the code (ovn_bgp_agent/drivers/openstack/watchers/nb_bgp_watcher.py:172-195).
sequenceDiagram autonumber participant N as Neutron participant NB as OVN NB participant A1 as Agent (cmp1) participant A2 as Agent (cmp2) N->>NB: LSP options:requested-chassis = "cmp1,cmp2" Note over A1,A2: no match: FIP unchanged, port still up on cmp1 NB-->>A1: LSP up true→false (port set down on source) Note over A1: LogicalSwitchPortFIPDeleteEvent → withdraw FIP (ip addr del, rule/route del) N->>NB: requested-chassis = "cmp2", neutron:host_id = cmp2 NB-->>A2: LSP up false→true (bound on cmp2) Note over A2: LogicalSwitchPortFIPCreateEvent → read NAT (external_ip, external_mac, fip_network_id) A2->>A2: wire FIP on provider switch neutron-<fip_network_id>, ip addr add FIP/32 dev bgp-nic
Diagnostics: if the FIP is announced by neither node after the migration, check the NAT row of the port (external_mac and external_ids:neutron:fip_network_id must be set; otherwise DEBUG … does not have all data required in its NAT entry). NATMACAddedEvent covers the case where Neutron sets external_mac after the port is up.
6. OVSDB reconnection (SB driver)
sequenceDiagram autonumber participant SB as OVN SB participant AG as Agent SB--xAG: connection lost (SB restart, network) AG->>SB: reconnect, monitor_cond again SB-->>AG: all rows as CREATE (incl. own Chassis_Private) Note over AG: events fire for replayed rows; ChassisPrivateCreateEvent (not first time) AG->>AG: "Connection to OVSDB established, doing a full sync" → sync()
Diagnostics: the NB driver and the stretched driver have no such hook; after an NB outage, state is repaired by the next timer sync (up to reconcile_interval seconds), and the NB sync cleanup removes IPs that should no longer be exposed (WARNING Removing IPs … as they are not expected to be exposed.).
Source: reverse-spec-ovn-bgp-agent/04-scenarios_stable-2026.2.md. The _rewrite/ and _inventory/ files are not published on the site.