Scenarios — ovn-octavia-provider — branch stable/2026.2
Branch
stable/2026.2@c56940998594(11.0.0-2-gc569409) — repository https://opendev.org/openstack/ovn-octavia-provider — analysed on 2026-10-28
Five end-to-end flows. Participants: the user, octavia-api (with the driver and its helper thread), the Octavia driver agent (sockets and the ovn provider agent), Neutron, the OVN NB/SB databases and ovn-northd/ovn-controller. References: octavia: is Octavia stable/2026.2 @ 2900ed67cac2.
1. Create a load balancer with a listener, a pool and a member
The user creates the objects one by one (the full-graph variant queues the same requests from a single loadbalancer_create, ovn_octavia_provider/driver.py:195-214).
sequenceDiagram
autonumber
actor U as User
participant API as octavia-api + driver
participant H as helper thread (API process)
participant N as Neutron
participant NB as OVN NB
participant DA as driver agent (status.sock)
U->>API: POST /v2/lbaas/loadbalancers (provider=ovn)
API->>N: POST /v2.0/ports ovn-lb-vip-<lb> (create_vip_port, synchronous)
alt Neutron 409 and no same-name port
API-->>U: 409 VIP address already in use
end
API->>H: queue lb_create
API-->>U: 201 PENDING_CREATE
H->>N: GET /v2.0/ports?network_id=… , GET /v2.0/subnets/{id}
H->>NB: transact insert Load_Balancer(name=lb, protocol=[], external_ids)
H->>NB: transact lr_lb_add / ls_lb_add (routers of the VIP subnet, VIP switch), ls_refs
H->>DA: status LB ACTIVE/ONLINE
U->>API: POST /v2/lbaas/listeners (TCP 80)
API->>H: queue listener_create
H->>NB: transact external_ids listener_<id>=80:, protocol=tcp, vips={}
H->>DA: listener ACTIVE/ONLINE, LB ACTIVE
U->>API: POST /v2/lbaas/pools (SOURCE_IP_PORT, listener)
API->>H: queue pool_create
H->>NB: transact external_ids pool_<id>='', listener value += pool_<id>, selection_fields
H->>DA: pool ACTIVE/ONLINE, listener ACTIVE, LB ACTIVE
U->>API: POST /v2/lbaas/pools/{id}/members (10.0.0.10:8080, subnet)
API->>H: queue member_create, handle_member_dvr
H->>NB: transact pool_<id>=member_<m>_10.0.0.10:8080_<subnet>, vips {"VIP:80": "10.0.0.10:8080"}
H->>NB: ls_lb_add member switch (ls_refs+1), lr_lb_add member routers
H->>NB: external_ids neutron:member_status {m: NO_MONITOR}
H->>DA: full tree: member NO_MONITOR, pool ONLINE, listener ONLINE, LB ONLINE
H->>NB: (handle_member_dvr) nothing unless LB VIP has a FIPDiagnostics:
- LB stuck in
PENDING_CREATE: the helper thread could not send the status (look forError while updating the load balancer statusand check that/var/run/octavia/status.sockis served,ovn_octavia_provider/helper.py:429-431), or a handler raised outside its owntry(Unexpected exception in request_handler,ovn_octavia_provider/helper.py:437). - LB
ERRORright after creation: Neutron lookup of the VIP port failed (Cannot get info from neutron,ovn_octavia_provider/helper.py:1583), or the NB transaction failed. The VIP port has been deleted, but the OVN row may remain (ovn_octavia_provider/helper.py:1732-1760). - Traffic not balanced while everything is
ACTIVE: checkovn-nbctl list Load_Balancer <lb>:vipsstays empty until a listener with a pool that has enabled members exists (ovn_octavia_provider/helper.py:1396-1406); check that the LB is in theload_balancercolumn of the client's switch or router (ls_refs,lr_ref).
2. Add a health monitor and react to a failing member
sequenceDiagram
autonumber
actor U as User
participant API as octavia-api + driver
participant H as helper thread
participant N as Neutron
participant NB as OVN NB
participant OVN as ovn-northd / ovn-controller
participant SB as OVN SB
participant AG as provider agent (event lock holder)
participant DA as driver agent (status.sock)
U->>API: POST /v2/lbaas/healthmonitors (TCP, delay 5, max_retries 3)
alt NB schema without Load_Balancer.health_check, or type HTTP/PING
API-->>U: 501 does not support a requested option
end
API->>H: queue hm_create
API-->>U: 201 PENDING_CREATE
H->>NB: transact insert Load_Balancer_Health_Check(vip "VIP:80", options), health_check += ref, octavia:healthmonitors
loop each member
H->>NB: read member LSP (address match on the member switch)
H->>N: GET/POST /v2.0/ports ovn-lb-hm-<subnet> (device_owner ovn-lb-hm:distributed)
H->>NB: ip_port_mappings[member ip] = "<member lsp>:<hm port ip>"
H->>NB: neutron:member_status {m: ONLINE}
end
H->>DA: HM ACTIVE/ONLINE, pool/listener ONLINE, members ONLINE
NB-->>OVN: ovn-northd creates SB Service_Monitor per backend
OVN->>SB: Service_Monitor.status = offline (member stops answering)
SB-->>AG: ServiceMonitorUpdateEvent (UPDATE)
AG->>NB: find Load_Balancer by ip_port_mappings + protocol
AG->>AG: queue hm_update_event
AG->>NB: neutron:member_status {m: ERROR}
AG->>DA: get.sock get_loadbalancer / get_pool / get_listener (admin states)
AG->>DA: status member ERROR, pool ERROR or DEGRADED, listener/LB DEGRADED or ERRORDiagnostics:
- HM
ERRORat creation: member LSP not found (Member %(member)s Logical_Switch_Port not found…,ovn_octavia_provider/helper.py:3861) or the HM port could not be created (No port on network…,ovn_octavia_provider/helper.py:3874). Check the Neutron portovn-lb-hm-<subnet id>and its NB LSPtype=localport. - Member statuses never change: no provider agent holds the event lock or the agent is not enabled (
[driver_agent] enabled_provider_agents = ovn,octavia:octavia/common/config.py:914); the SBService_Monitortable is empty (wrongip_port_mappings, see the IPv6 bracket fix in 05 § 4.3); or the event names an IP/port not in any pool (Member for event not found,ovn_octavia_provider/helper.py:4436). - The HM was created before the listener: its
vipis''and is only set when the listener is created (ovn_octavia_provider/helper.py:3512,ovn_octavia_provider/helper.py:2114-2121).
3. Attach a floating IP to the VIP
sequenceDiagram
autonumber
actor U as User
participant N as Neutron (OVN mech driver)
participant NB as OVN NB
participant AG as provider agent
participant H as agent helper thread
U->>N: PUT /v2.0/floatingips/{id} port_id=<VIP port>
N->>NB: NAT dnat_and_snat, LSP ovn-lb-vip-<lb>.external_ids neutron:port_fip=<FIP>
NB-->>AG: LogicalSwitchPortUpdateEvent (external_ids changed, name ovn-lb-vip-*)
AG->>N: GET /v2.0/ports/{vip port}
AG->>H: queue handle_vip_fip (associate) per OVN row of the LB
H->>NB: external_ids neutron:vip_fip=<FIP>, extra Load_Balancer_Health_Check for the FIP, vips += "FIP:80"
Note over H,NB: No status is sent: the FIP is not an Octavia objectIf members also have FIPs, the next member_create centralises their NAT (external_mac/logical_port cleared, ovn_octavia_provider/helper.py:3374-3385). Diagnostics: the FIP does not answer while the VIP does → check neutron:vip_fip on the OVN row and that vips has a FIP:port key (IPv4 only, ovn_octavia_provider/helper.py:1428-1437); run octavia-ovn-db-sync-util to re-apply it (ovn_octavia_provider/driver.py:856-897).
4. Add a router interface to a member network
sequenceDiagram
autonumber
actor U as User
participant N as Neutron
participant NB as OVN NB
participant AG as provider agent
participant H as agent helper thread
U->>N: PUT /v2.0/routers/{id}/add_router_interface subnet=S2
N->>NB: insert Logical_Router_Port lrp-<port>, LSP type=router
NB-->>AG: LogicalRouterPortEvent (CREATE)
AG->>NB: lookup Logical_Router neutron-<router>, Logical_Switch neutron-<net>
AG->>H: queue lb_create_lrp_assoc (is_gw_port from neutron:is_ext_gw)
H->>NB: lr_lb_add for LBs of the switch; ls_lb_add on the router's switches
H->>NB: unless gateway port: ls_lb_add for the router's LBs on the new switchDiagnostics: clients on the new network cannot reach the VIP → the LB is missing from the new switch's load_balancer column; look for The association of loadbalancer %s to the logical switch %s failed (ovn_octavia_provider/helper.py:336-338). LBs on provider networks are never attached to their own switch (ovn_octavia_provider/helper.py:1022-1030).
5. Delete a load balancer in cascade
sequenceDiagram
autonumber
actor U as User
participant API as octavia-api + driver
participant H as helper thread
participant N as Neutron
participant NB as OVN NB
participant DA as driver agent
U->>API: DELETE /v2/lbaas/loadbalancers/{id}?cascade=true
API->>H: queue lb_delete (cascade)
API-->>U: 204
H->>NB: find Load_Balancer rows name=<lb>
alt no OVN row
H->>DA: get.sock get_loadbalancer (VIP port id)
H->>N: DELETE /v2.0/ports/{vip} if name ovn-lb-vip-*
H->>DA: LB DELETED
else rows found
loop each row (one per protocol)
H->>NB: member_delete per pool (ip_port_mappings, ls_refs, vips)
H->>N: PUT /v2.0/floatingips/{member fip} (empty update) if LB and member have FIPs
H->>NB: transact clear health_check, ls_lb_del, lr_lb_del, lb_del
H->>N: DELETE /v2.0/ports/{ovn-lb-hm-subnet} when unused
end
H->>N: DELETE /v2.0/ports/{vip} (if provider-created), additional VIP ports
H->>DA: LB DELETED, listeners/pools/members/HMs DELETED
endDiagnostics: LB ERROR after delete → Exception occurred during deletion of loadbalancer (ovn_octavia_provider/helper.py:1864); a user-provided VIP port is kept on purpose (Preserving user-provided VIP port %s, ovn_octavia_provider/helper.py:1855); leftover Load_Balancer_Health_Check rows are removed by the next sync (hm_purge, ovn_octavia_provider/helper.py:4463-4500).
Source: reverse-spec-ovn-octavia-provider/04-scenarios_stable-2026.2.md. The _rewrite/ and _inventory/ files are not published on the site.