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

Reverse-spec · Services

neutron — Interactions

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 (ovs 3.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_cert and 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_periodics on NB (lock method of RFC 7047), see 05 § 4.1.
  • Synchronous or not: writes are synchronous inside the API request, after the SQL commit (postcommit and AFTER_* 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 resourceNB rowsWritten at
networkLogical_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 portsneutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py:2414-2494, 2306
subnetDHCP_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
portLogical_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 recordsneutron/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 subnetneutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py:3168-3310
security group / rulePort_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 groupAddress_Set per IP versionneutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py:3115-3165
routerLogical_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 subnetneutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py:1647-1806
router interface / gatewayLogical_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-portneutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py:1928-2272
floating IPNAT 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 forwardingLoad_Balancer pf-floatingip-<fip id>-<proto> attached to the router (and the switch)neutron/services/portforwarding/drivers/ovn/driver.py:95-133
QoSQoS rows on the logical switch for port bandwidth/DSCP; Meters for FIP and gateway policiesneutron/services/qos/drivers/ovn/driver.py, neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/extensions/qos.py
network loglog, meter, severity, name on ACLs; Meter acl_log_meterneutron/services/logapi/drivers/ovn/driver.py
globalNB_Global.options from [ovn_nb_global]; NB_Global.nb_cfg bumped for liveness; NB_Global.external_ids:neutron:liveness_check_atneutron/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_ids of metadata/OVN agents), Port_Binding (chassis, up, virtual_parent), Datapath_Binding, Encap — for port binding, agents, gateway scheduling (05 § 3).
  • Writes: deletes MAC_Binding rows of a floating IP's external IP with a raw transact through ovsdb-client (neutron/plugins/ml2/drivers/ovn/mech_driver/mech_driver.py:1540-1552); writes SB_Global.external_ids:delete_agent to 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 enginefacade through neutron_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 to MAX_RETRIES = 20 with exponential back-off on DBDeadlock, DBConnectionError, DBDuplicateEntry (some), StaleDataError, RetryRequest (neutron-lib:neutron_lib/db/api.py:40, 159).
  • Locking: optimistic, through standardattributes.revision_number (SQLAlchemy version_id_col): a concurrent update raises StaleDataError → retry; If-Match turns it into a 412 (01 § 2.3). IP allocation relies on unique constraints and retries rather than SELECT … FOR UPDATE. Network-level serialisation of subnet operations uses network_subnet_lock (neutron/db/models_v2.py).
  • Migrations: Alembic, branches expand and contract per release under neutron/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)

GroupTablesWritten byRead by
core L2networks, subnets, ports, ipallocations, ipallocationpools, dnsnameservers, subnetroutes, subnetpools, subnetpoolprefixes, address_scopes, externalnetworks, network_subnet_lockAPI (network/subnet/port/subnetpool calls)API, maintenance, sync
IPAMipamsubnets, ipamallocationpools, ipamallocationsIPAM driver internal (neutron/ipam/drivers/neutrondb_ipam/driver.py)IPAM
common attributesstandardattributes (id, resource_type, description, revision_number, created_at, updated_at), tags, provisioningblocksevery write; tags API; provisioning blocks (05)everything
ML2networksegments, 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_rangesML2, segments plugin, OVN ChassisEventML2
port extensionsportsecuritybindings, networksecuritybindings, allowedaddresspairs, extradhcpopts, portdnses, networkdnsdomains, portdataplanestatuses, portnumaaffinitypolicies, portdeviceprofiles, porthardwareoffloadtype, porthints, porttrusted, portuplinkstatuspropagationport APIport API, OVN client
L3routers, routerports, routerroutes, router_extra_attributes, floatingips, portforwardings, ha_router_* (unused by OVN)L3 APIOVN client, maintenance
securitysecuritygroups, securitygrouprules, securitygroupportbindings, default_security_group, securitygroupdefaultrules, security_groups_default_statefulness, address_groups, address_associationsSG APIOVN client
QoSqos_policies, qos_policies_default, qos_*_rules, qos_port_policy_bindings, qos_network_policy_bindings, qos_fip_policy_bindings, qos_router_gw_policy_bindingsQoS APIQoS OVN driver
RBACnetworkrbacs, qospolicyrbacs, securitygrouprbacs, addressscoperbacs, subnetpoolrbacs, addressgrouprbacsRBAC APIevery query of a shareable resource (joined to compute visibility)
quotasquotas, quotausages, reservations, resourcedeltasquota enginequota engine
trunkstrunks, subportstrunk APIOVN trunk driver
agents, miscagents (non-OVN agents only), logs, flavors, serviceprofiles, flavorserviceprofilebindings, providerresourceassociations, auto_allocated_topologiesAPIs, RPC report_stateAPIs
OVNovn_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, maintenancemaintenance, OVSDB event dispatch

2.3 Notable transactions

  • Create port (neutron/plugins/ml2/plugin.py:1637-1680): one write transaction inserts standardattributes, ports, ipallocations/ipamallocations, ml2_port_bindings, securitygroupportbindings, extension rows, ovn_revision_numbers (precommit) and possibly provisioningblocks; 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 (via session.merge, never lowering the value) (neutron/db/ovn_revision_numbers_db.py:183-221).

3. RabbitMQ (oslo.messaging)

3.1 Notifications

event_typePriorityEmitted whenPayloadEmitted at
<resource>.create.startINFObefore a createrequest bodyneutron/api/v2/base.py:438-442, neutron/pecan_wsgi/hooks/notifier.py:37-62
<resource>.create.endINFOafter a successful create{"<resource>": {...}} API viewneutron/api/v2/base.py:502-521, neutron/pecan_wsgi/hooks/notifier.py:64-112
<resource>.update.start / .endINFObefore / after an updatebody + id / API viewneutron/api/v2/base.py:619-709
<resource>.delete.start / .endINFObefore / 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 serviceMethod + pathWhenAuthenticationTimeout / retryErrors handledDefined at
KeystoneGET /v3/auth/tokens (via keystonemiddleware auth_token)every API request whose token is not cachedservice credentials of [keystone_authtoken][keystone_authtoken] options; memcached cacheinvalid token → 401 before Neutron codeetc/neutron/api-paste.ini:40-41
NovaPOST /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 skeystoneauth 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 droppedneutron/notifiers/nova.py:70-300
PlacementGET/POST /resource_providers, PUT /resource_providers/{uuid}/inventories, PUT …/traitsSB Chassis changes with bandwidth configuration (QoS minimum bandwidth)keystoneauth session from [placement]batch notifierlogged; agent resources_synced flagneutron/services/placement_report/plugin.py:58-202
Designatezone/recordset callsonly 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 transact to delete SB MAC_Binding rows (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.

PeerProtocolDirectionWhatDefined at
OVN SBOVSDB ([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_Privateneutron/agent/ovn/metadata/agent.py:444-455
OVN SBOVSDB transactwriteChassis_Private.external_ids: neutron:ovn-metadata-id, neutron:ovn-bridge, neutron:ovn-metadata-sb-cfg (heartbeat); removal of the neutron-ovn-agent keys at startneutron/agent/ovn/metadata/agent.py:385-426, 481-489, 311-315
local OVSOVSDB on the local socket ([ovs]/ovsdb_connection)read/writeOpen_vSwitch.external_ids (system-id, ovn-bridge), add/del the veth port on the OVN bridge with Interface.external_ids:iface-idneutron/agent/ovn/metadata/ovsdb.py:66-80, neutron/agent/ovn/metadata/agent.py:828-850
Linux kernelnetlink (pyroute2 via privsep)writenamespaces ovnmeta-<net id>, veth pairs, addresses, MTU; iptables mangle rule on DPDKneutron/agent/ovn/metadata/agent.py:575-617, 776-823
haproxyprocess + Unix socketspawn / receiveone haproxy per network namespace; HTTP over the Unix socket [DEFAULT]/metadata_proxy_socketneutron/agent/metadata/driver_base.py:259-335
Nova metadata APIHTTP/HTTPSoutboundGET <path> on nova_metadata_host:nova_metadata_portneutron/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.