OpenKeel: the sovereign French Cloud solution of the inherent group, with a European reach Discover inherent

Reverse-spec · Services

ovn-bgp-agent — Scenarios

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)
  end

Diagnostics: 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)
  end

Diagnostics: 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
  end

Diagnostics: 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 router

Diagnostics: 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.