Interactions with other components — neutron — branch stable/2026.2
Branch
stable/2026.2@eef1a0f7ee36— repository https://opendev.org/openstack/neutron — analysed on 2026-10-28
Scope: neutron-server processes in the ML2/OVN reference profile (see 01-rest-api_stable-2026.2.md and 05-async-processing_stable-2026.2.md). The OVN metadata agent's exchanges are in § 6.
flowchart LR
client[Clients: Nova, Octavia, Horizon, CLI] -->|HTTPS REST /v2.0| api[neutron API workers]
api -->|validate token| ks[Keystone]
api -->|SQL| db[(MariaDB)]
rpc[neutron-rpc-server] -->|SQL| db
maint[neutron-ovn-maintenance-worker] -->|SQL| db
api -->|OVSDB JSON-RPC 6641: transact + monitor| nb[(OVN Northbound)]
api -->|OVSDB 6642: monitor, few writes| sb[(OVN Southbound)]
maint -->|OVSDB + lock| nb
maint --> sb
nb --> northd[ovn-northd] --> sb
sb --> ctl[ovn-controller per node]
api -->|POST os-server-external-events| nova[Nova]
api -->|REST resource providers| placement[Placement]
api -->|AMQP notifications| mq{{RabbitMQ}}
oldagents[non-OVN agents: SR-IOV, DHCP, L3 if deployed] -->|AMQP RPC q-plugin, q-reports-plugin| mq --> rpc
meta[OVN metadata agent / neutron-ovn-agent per node] -->|OVSDB 6642: monitor + Chassis_Private writes| sb
meta -->|OVSDB local: Open_vSwitch, Bridge, Port, Interface| ovs[(local ovsdb-server)]
vm[VM] -->|HTTP 169.254.169.254:80 in ovnmeta-<net> namespace| haproxy[haproxy per network]
haproxy -->|HTTP over Unix socket + X-OVN-Network-ID| meta
meta -->|HTTP GET + X-Instance-ID, X-Tenant-ID, X-Instance-ID-Signature| novameta[nova-metadata-api :8775]1. OVN Northbound and Southbound databases (OVSDB)
1.1 Protocol and connection
- Protocol: OVSDB management protocol (RFC 7047, JSON-RPC 1.0) over TCP, SSL or a Unix socket; NB on port 6641, SB on 6642. Library:
ovsdbapp(2.19.0 in the extraction venv) on top of the Open vSwitch Python IDL (ovs3.7.1). - Endpoints:
[ovn]/ovn_nb_connection,[ovn]/ovn_sb_connection(comma-separated list for a RAFT cluster). SSL key, certificate and CA:[ovn]/ovn_nb_private_key,ovn_nb_certificate,ovn_nb_ca_certand the SB equivalents (neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovsdb_monitor.py:1192-1209). - Timeouts:
[ovn]/ovsdb_connection_timeout(180 s, per transaction),[ovn]/ovsdb_retry_max_interval(180 s, reconnection back-off),[ovn]/ovsdb_probe_interval(60 000 ms, inactivity probe) (neutron/conf/plugins/ml2/drivers/ovn/ovn_conf.py:86-100). The initial connection is retried with exponential back-off (neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/impl_idl_ovn.py:260-300). - Clustered databases: the NB connection follows the RAFT leader; the SB IDL of the server is opened with
leader_only=False(it may read from followers) (neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovsdb_monitor.py:1175). - Lock: the maintenance worker takes the OVSDB lock
ovn_db_inconsistencies_periodicson NB (lockmethod of RFC 7047), see 05 § 4.1. - Synchronous or not: writes are synchronous inside the API request, after the SQL commit (
postcommitandAFTER_*callbacks); reads use the local in-memory replica (no round trip).
1.2 What the server writes in NB
Every object carries external_ids with neutron:revision_number and the Neutron name/ID; that is how Neutron recognises its rows and how the maintenance task compares revisions.
| Neutron resource | NB rows | Written at |
|---|---|---|
| network | Logical_Switch neutron-<net id> (external_ids: neutron:network_name, neutron:mtu, neutron:revision_number, neutron:availability_zone_hints, network type, physnet; other_config: mcast_snoop, mcast_flood_unregistered, vlan-passthru, fdb_age_threshold, broadcast-arps-to-all-routers); one localnet LSP provnet-<segment id> per segment with a physical network; HA_Chassis_Group for external ports | neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py:2414-2494, 2306 |
| subnet | DHCP_Options (cidr, options: router, server_id, server_mac, lease_time, dns_server, classless_static_route, mtu…; external_ids: subnet_id, revision) | neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py:2735-2984 |
| port | Logical_Switch_Port named <port id> (addresses "MAC IP…", port_security, type ("", router, localport, external, virtual, localnet), options (requested-chassis, virtual-ip…), parent_name/tag for trunk sub-ports, dhcpv4_options, dhcpv6_options, enabled, external_ids (neutron:device_owner, neutron:device_id, neutron:cidrs, neutron:security_group_ids, neutron:host_id…)); membership of Port_Groups; DNS records | neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py:423-551, 596-716 |
metadata port (network:distributed) | LSP of type: localport holding the metadata IP of each subnet | neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py:3168-3310 |
| security group / rule | Port_Group pg_<sg id with _>; one ACL per rule (direction from-lport/to-lport, priority 1002, match like outport == @pg_… && ip4 && ip4.src == 10.0.0.0/24 && tcp && tcp.dst >= 22 && tcp.dst <= 22, action allow-related or allow-stateless, external_ids:neutron:security_group_rule_id); neutron_pg_drop with drop ACLs at priority 1000 (neutron/common/ovn/constants.py:116-118) | neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py:3033-3095, neutron/common/ovn/acl.py |
| address group | Address_Set per IP version | neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py:3115-3165 |
| router | Logical_Router neutron-<router id> (options: always_learn_from_arp_request, dynamic_neigh_routers, mac_binding_age_threshold), Logical_Router_Static_Route (default route via the external gateway, extra routes), NAT snat per private subnet | neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py:1647-1806 |
| router interface / gateway | Logical_Router_Port lrp-<port id> (mac, networks, ha_chassis_group for the gateway, options:redirect-type), the LSP of the port becomes type: router with options:router-port | neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py:1928-2272 |
| floating IP | NAT dnat_and_snat (logical_ip, external_ip, logical_port and external_mac when distributed, options:stateless, external_ids neutron:fip_id, neutron:fip_port_id, neutron:fip_external_mac, neutron:router_name) | neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py:1010-1112 |
| port forwarding | Load_Balancer pf-floatingip-<fip id>-<proto> attached to the router (and the switch) | neutron/services/portforwarding/drivers/ovn/driver.py:95-133 |
| QoS | QoS rows on the logical switch for port bandwidth/DSCP; Meters for FIP and gateway policies | neutron/services/qos/drivers/ovn/driver.py, neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/extensions/qos.py |
| network log | log, meter, severity, name on ACLs; Meter acl_log_meter | neutron/services/logapi/drivers/ovn/driver.py |
| global | NB_Global.options from [ovn_nb_global]; NB_Global.nb_cfg bumped for liveness; NB_Global.external_ids:neutron:liveness_check_at | neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/maintenance.py:1088-1101, neutron/plugins/ml2/drivers/ovn/mech_driver/mech_driver.py:1620-1638 |
1.3 What the server reads or writes in SB
- Reads
Chassis(hostname,other_config:ovn-bridge-mappings,ovn-cms-options,datapath-type,iface-types),Chassis_Private(nb_cfg,nb_cfg_timestamp,external_idsof metadata/OVN agents),Port_Binding(chassis,up,virtual_parent),Datapath_Binding,Encap— for port binding, agents, gateway scheduling (05 § 3). - Writes: deletes
MAC_Bindingrows of a floating IP's external IP with a rawtransactthroughovsdb-client(neutron/plugins/ml2/drivers/ovn/mech_driver/mech_driver.py:1540-1552); writesSB_Global.external_ids:delete_agentto tell all workers that an agent was deleted (DELETE /agents/{id}).
1.4 Sample frames
Transaction sent for POST /v2.0/networks (simplified, one transact per OVSDB transaction):
{"id": 42, "method": "transact", "params": ["OVN_Northbound",
{"op": "insert", "table": "Logical_Switch", "uuid-name": "row1",
"row": {"name": "neutron-3c7f…",
"external_ids": ["map", [["neutron:network_name", "net1"], ["neutron:mtu", "1442"],
["neutron:revision_number", "1"], ["neutron:availability_zone_hints", ""],
["neutron:network_type", "geneve"]]],
"other_config": ["map", [["mcast_snoop", "false"], ["mcast_flood_unregistered", "false"],
["vlan-passthru", "false"]]]}},
{"op": "comment", "comment": "ovsdbapp"}]}
Reply: {"id": 42, "result": [{"uuid": ["uuid", "…"]}, {}], "error": null}. A failed operation gives {"error": "constraint violation", "details": "…"} in the result array; ovsdbapp raises it and the API call fails (02 § 4).
Update pushed to every worker when ovn-controller claims a port (monitor_cond_since / update3):
{"id": null, "method": "update3", "params": ["<monitor id>", "<last txn id>",
{"Logical_Switch_Port": {"<row uuid>": {"modify": {"up": true}}}}]}
2. Database (MariaDB / MySQL)
2.1 Access
- oslo.db
enginefacadethroughneutron_lib.db.api.CONTEXT_READER/CONTEXT_WRITER(neutron-lib:neutron_lib/db/api.py);[database]/connection(mysql+pymysql://…). Versioned objects (neutron/objects/) wrap most tables. - Retries: every API handler and many internal functions are decorated with
retry_db_errors/retry_if_session_inactive: up toMAX_RETRIES= 20 with exponential back-off onDBDeadlock,DBConnectionError,DBDuplicateEntry(some),StaleDataError,RetryRequest(neutron-lib:neutron_lib/db/api.py:40,159). - Locking: optimistic, through
standardattributes.revision_number(SQLAlchemyversion_id_col): a concurrent update raisesStaleDataError→ retry;If-Matchturns it into a 412 (01 § 2.3). IP allocation relies on unique constraints and retries rather thanSELECT … FOR UPDATE. Network-level serialisation of subnet operations usesnetwork_subnet_lock(neutron/db/models_v2.py). - Migrations: Alembic, branches
expandandcontractper release underneutron/db/migration/alembic_migrations/versions/(neutron-db-manage upgrade --expand,--contract); the generated DDL and the migrated schema are in_rewrite/(step 8).
2.2 Tables (117 in the models)
| Group | Tables | Written by | Read by |
|---|---|---|---|
| core L2 | networks, subnets, ports, ipallocations, ipallocationpools, dnsnameservers, subnetroutes, subnetpools, subnetpoolprefixes, address_scopes, externalnetworks, network_subnet_lock | API (network/subnet/port/subnetpool calls) | API, maintenance, sync |
| IPAM | ipamsubnets, ipamallocationpools, ipamallocations | IPAM driver internal (neutron/ipam/drivers/neutrondb_ipam/driver.py) | IPAM |
| common attributes | standardattributes (id, resource_type, description, revision_number, created_at, updated_at), tags, provisioningblocks | every write; tags API; provisioning blocks (05) | everything |
| ML2 | networksegments, segmenthostmappings, ml2_port_bindings (host, vif_type, vnic_type, profile, vif_details, status ACTIVE/INACTIVE), ml2_port_binding_levels, ml2_distributed_port_bindings, ml2_geneve_allocations, ml2_vlan_allocations, ml2_flat_allocations, ml2_vxlan_allocations, network_segment_ranges | ML2, segments plugin, OVN ChassisEvent | ML2 |
| port extensions | portsecuritybindings, networksecuritybindings, allowedaddresspairs, extradhcpopts, portdnses, networkdnsdomains, portdataplanestatuses, portnumaaffinitypolicies, portdeviceprofiles, porthardwareoffloadtype, porthints, porttrusted, portuplinkstatuspropagation | port API | port API, OVN client |
| L3 | routers, routerports, routerroutes, router_extra_attributes, floatingips, portforwardings, ha_router_* (unused by OVN) | L3 API | OVN client, maintenance |
| security | securitygroups, securitygrouprules, securitygroupportbindings, default_security_group, securitygroupdefaultrules, security_groups_default_statefulness, address_groups, address_associations | SG API | OVN client |
| QoS | qos_policies, qos_policies_default, qos_*_rules, qos_port_policy_bindings, qos_network_policy_bindings, qos_fip_policy_bindings, qos_router_gw_policy_bindings | QoS API | QoS OVN driver |
| RBAC | networkrbacs, qospolicyrbacs, securitygrouprbacs, addressscoperbacs, subnetpoolrbacs, addressgrouprbacs | RBAC API | every query of a shareable resource (joined to compute visibility) |
| quotas | quotas, quotausages, reservations, resourcedeltas | quota engine | quota engine |
| trunks | trunks, subports | trunk API | OVN trunk driver |
| agents, misc | agents (non-OVN agents only), logs, flavors, serviceprofiles, flavorserviceprofilebindings, providerresourceassociations, auto_allocated_topologies | APIs, RPC report_state | APIs |
| OVN | ovn_revision_numbers (standard_attr_id FK ON DELETE SET NULL, resource_uuid, resource_type, revision_number, created_at, updated_at) (neutron/db/models/ovn.py:22); ovn_hash_ring (node_uuid, group_name, hostname, created_at, updated_at) (neutron/db/models/ovn.py:49) | OVN driver, maintenance | maintenance, OVSDB event dispatch |
2.3 Notable transactions
- Create port (
neutron/plugins/ml2/plugin.py:1637-1680): one write transaction insertsstandardattributes,ports,ipallocations/ipamallocations,ml2_port_bindings,securitygroupportbindings, extension rows,ovn_revision_numbers(precommit) and possiblyprovisioningblocks; the OVN write and the binding come after the commit, each binding attempt in its own transaction (neutron/plugins/ml2/plugin.py:651-735). - Revision bump after each OVN write:
UPDATE ovn_revision_numbers SET revision_number = :n WHERE standard_attr_id = :id AND resource_type = :t(viasession.merge, never lowering the value) (neutron/db/ovn_revision_numbers_db.py:183-221).
3. RabbitMQ (oslo.messaging)
3.1 Notifications
| event_type | Priority | Emitted when | Payload | Emitted at |
|---|---|---|---|---|
<resource>.create.start | INFO | before a create | request body | neutron/api/v2/base.py:438-442, neutron/pecan_wsgi/hooks/notifier.py:37-62 |
<resource>.create.end | INFO | after a successful create | {"<resource>": {...}} API view | neutron/api/v2/base.py:502-521, neutron/pecan_wsgi/hooks/notifier.py:64-112 |
<resource>.update.start / .end | INFO | before / after an update | body + id / API view | neutron/api/v2/base.py:619-709 |
<resource>.delete.start / .end | INFO | before / after a delete | {"<resource>_id"} / {"<resource>_id", "<resource>": {...}} | neutron/api/v2/base.py:566-617 |
publisher_id is network.<host> (neutron-lib:neutron_lib/rpc.py:230-253). The transport, driver (messagingv2, log, noop) and topics come from [oslo_messaging_notifications]; with the default (no driver) nothing is sent. Designate's sink and Ceilometer consume them. Sample envelope on the notifications.info queue of exchange neutron:
{"oslo.version": "2.0", "oslo.message": "{\"message_id\": \"…\", \"publisher_id\": \"network.ctl1\", \"event_type\": \"port.create.end\", \"priority\": \"INFO\", \"payload\": {\"port\": {\"id\": \"…\", \"network_id\": \"…\", \"status\": \"DOWN\", …}}, \"timestamp\": \"2026-10-28 10:00:00.000000\", \"_context_project_id\": \"…\", \"_context_request_id\": \"req-…\"}"}
3.2 RPC served by neutron-rpc-server
Only when [DEFAULT]/rpc_workers > 0. Consumers (neutron/plugins/ml2/plugin.py:452-469): topic q-plugin with endpoints RpcCallbacks (get_device_details, update_device_up/down…), SecurityGroupServerRpcCallback, DVRServerRpcCallback, DhcpRpcCallback, AgentExtRpcCallback, MetadataRpcCallback, ResourcesPullRpcCallback (neutron/plugins/ml2/plugin.py:320-330); topic q-reports-plugin (agent report_state heartbeats → table agents); fanout topic q-server-resource-versions. With OVN, no OVN component uses this RPC: the OVN metadata agent and neutron-ovn-agent only talk to the SB database (§ 6); the clients are other agents deployed next to OVN (SR-IOV NIC agent, DHCP agent for baremetal…). ML2/OVN does not send port_update/security-group fan-outs to agents (neutron/plugins/ml2/plugin.py:444-445). The RPC method tables are in _inventory/inventory_stable-2026.2.json (triggers, rpc).
4. Outbound REST calls
| Target service | Method + path | When | Authentication | Timeout / retry | Errors handled | Defined at |
|---|---|---|---|---|---|---|
| Keystone | GET /v3/auth/tokens (via keystonemiddleware auth_token) | every API request whose token is not cached | service credentials of [keystone_authtoken] | [keystone_authtoken] options; memcached cache | invalid token → 401 before Neutron code | etc/neutron/api-paste.ini:40-41 |
| Nova | POST /os-server-external-events {"events": [{"name": "network-vif-plugged", "server_uuid": "<device_id>", "status": "completed", "tag": "<port id>"}]} | port status changes, port deletion, fixed IP / FIP changes of compute:* ports, batched every 2 s | keystoneauth session from [nova] (auth_type, region_name, endpoint_type) | retry on connection failure for 1 s (tenacity) | EndpointNotFound → session invalidated; NotFound (unknown instance) → debug log; other errors logged; events dropped | neutron/notifiers/nova.py:70-300 |
| Placement | GET/POST /resource_providers, PUT /resource_providers/{uuid}/inventories, PUT …/traits | SB Chassis changes with bandwidth configuration (QoS minimum bandwidth) | keystoneauth session from [placement] | batch notifier | logged; agent resources_synced flag | neutron/services/placement_report/plugin.py:58-202 |
| Designate | zone/recordset calls | only with [DEFAULT]/external_dns_driver = designate (not in the reference profile) | [designate] | — | — | neutron/services/externaldns/drivers/designate/driver.py |
5. Other
- Binaries: the server runs
ovsdb-client transactto delete SBMAC_Bindingrows (neutron/common/ovn/utils.py,OvsdbClientTransactCommand), with the SB SSL options. - Files:
[DEFAULT]/state_path; the healthcheck file/var/lib/neutron/healthcheck_disable. - No privileged operation (privsep/rootwrap) runs in the server with ML2/OVN.
6. OVN metadata agent (every compute node)
Processing in 05-async-processing_stable-2026.2.md § 5. The agent has no database and no AMQP connection.
| Peer | Protocol | Direction | What | Defined at |
|---|---|---|---|---|
| OVN SB | OVSDB ([ovn]/ovn_sb_connection of the agent's config) | read (monitor) | Port_Binding of the chassis and of the metadata localports, Datapath_Binding, SB_Global.nb_cfg, Chassis, Chassis_Private | neutron/agent/ovn/metadata/agent.py:444-455 |
| OVN SB | OVSDB transact | write | Chassis_Private.external_ids: neutron:ovn-metadata-id, neutron:ovn-bridge, neutron:ovn-metadata-sb-cfg (heartbeat); removal of the neutron-ovn-agent keys at start | neutron/agent/ovn/metadata/agent.py:385-426, 481-489, 311-315 |
| local OVS | OVSDB on the local socket ([ovs]/ovsdb_connection) | read/write | Open_vSwitch.external_ids (system-id, ovn-bridge), add/del the veth port on the OVN bridge with Interface.external_ids:iface-id | neutron/agent/ovn/metadata/ovsdb.py:66-80, neutron/agent/ovn/metadata/agent.py:828-850 |
| Linux kernel | netlink (pyroute2 via privsep) | write | namespaces ovnmeta-<net id>, veth pairs, addresses, MTU; iptables mangle rule on DPDK | neutron/agent/ovn/metadata/agent.py:575-617, 776-823 |
| haproxy | process + Unix socket | spawn / receive | one haproxy per network namespace; HTTP over the Unix socket [DEFAULT]/metadata_proxy_socket | neutron/agent/metadata/driver_base.py:259-335 |
| Nova metadata API | HTTP/HTTPS | outbound | GET <path> on nova_metadata_host:nova_metadata_port | neutron/agent/metadata/proxy_base.py:185-251 |
Sample request seen by Nova:
GET /openstack/latest/meta_data.json HTTP/1.1
Host: 127.0.0.1:8775
X-Forwarded-For: 10.0.0.12
X-Instance-ID: 6f0c1d4e-…
X-Tenant-ID: 9a7b…
X-Instance-ID-Signature: 3b1c…(hex HMAC-SHA256 of the instance ID with metadata_proxy_shared_secret)
Nova recomputes the signature with its own [neutron]/metadata_proxy_shared_secret and refuses with 403 when they differ.
Source: reverse-spec-neutron/03-interactions_stable-2026.2.md. The _rewrite/ and _inventory/ files are not published on the site.