Skip to content

Neutron Operator ​

The Neutron operator runs the OpenStack network service on one mechanism driver. mechanism_drivers = ovn is what the rendered ml2_conf.ini carries, and no other value is reachable through the CRD. There is no ML2/OVS stack under it and no agent tier beside it: no L2, L3 or DHCP agent is projected, no neutron-dynamic-routing, and no BGP agent. The logical network model lives in the OVN Northbound database the OVN operator runs, and this operator programs it through the ML2/OVN mechanism driver.

Processes ​

Three long-running processes carry the service, plus the per-node agent:

ProcessWorkloadWhat it does
uWSGI on neutron.wsgi.apithe {name} Deployment of a NeutronThe REST API on port 9696. The image ships no entry script, so uWSGI loads the module directly, and the configuration reaches it through OS_NEUTRON_CONFIG_DIR and OS_NEUTRON_CONFIG_FILES
neutron-periodic-workersthe {name}-periodic-workers DeploymentThe recurring maintenance tasks of the ML2 plugin
neutron-ovn-maintenance-workerthe {name}-ovn-maintenance-worker DeploymentReconciles the Northbound model against the Neutron database
neutron-ovn-metadata-agentthe {name}-metadata-agent DaemonSet of a NeutronMetadataAgentAnswers the 169.254.169.254 requests of the instances on its node

neutron-rpc-server is absent from that list. Nothing in this deployment consumes RPC, so the process has no work, and at rpc_workers = 0 it exits 0 on 2026.1. Both worker Deployments serve no HTTP and get no Service, no HorizontalPodAutoscaler and no PodDisruptionBudget.

The bus ​

Neutron never touches the broker in this posture. rpc_workers and rpc_state_report_workers are both 0, [oslo_messaging_notifications] driver is noop, and dhcp_agent_notification together with the two notify_nova_on_port_* options stays false. Measured across four states, including after a network create, that adds up to zero connections, zero channels, zero queues and zero non-default exchanges.

A valid transport_url is still required. config.init calls n_rpc.init unconditionally in every neutron process, so the URL has to parse even though nothing dials the broker with it. spec.messaging is therefore a required field on Neutron, and the URL reaches every process and every migration Job as the OS_DEFAULT__TRANSPORT_URL environment override sourced from the derived {name}-transport-url Secret. It is never written into the rendered configuration, so the broker password stays out of the ConfigMap.

The two kinds ​

Neutron describes the service: the API Deployment, the two worker Deployments, the database and cache connections, the Keystone integration, the bus, and the optional recurring comparison of the Neutron database against the OVN Northbound database. It names one OVNCentral through spec.ovn.centralRef, reads the two connection strings and the client certificate off that CR's status, and mirrors the certificate into a Secret of its own.

The figure shows the OVNCentral a Neutron names and the other clients of its two databases.

What one OVNCentral runs and who talks to it. The Northbound database {central}-nb and the Southbound database {central}-sb are Raft clusters of three members each by default. northd reads the Northbound database and writes the flows into the Southbound database. A relay in front of the Southbound database exists only with spec.relay. A CronJob backs both databases up, and cert-manager issues a server certificate per database, one for the relay and one client certificate from the ClusterIssuer that spec.tls.issuerRef names. On the Neutron side the API with its ML2/OVN driver, the maintenance worker and the periodic workers hold both connections, and the optional CronJob {neutron}-ovn-db-sync compares the Northbound database with the Neutron database or rewrites it. On every chassis node ovn-controller registers the chassis in the Southbound database and reads its flows there, and the metadata agent watches the Southbound database and writes its Chassis_Private row. Two Jobs of an OVNChassis write as well: the evacuation removes gateway bindings from the Northbound database, and the chassis deletion removes the chassis row from the Southbound database. Only ovn-controller is pointed at the relay; every other client dials the database members.

NeutronMetadataAgent describes the per-node metadata proxy. It names an OVNChassis and puts one DaemonSet onto the nodes that chassis selects. The kind is separate because it belongs in the chassis's namespace: the pods are privileged, run on the compute and network nodes, and mount the local Open vSwitch socket the chassis pods create. That namespace has to be listed under privilegedNamespaces in the target-cluster access chart, which the API Deployment's namespace does not. See Target Clusters.

Design decisions ​

The Phase-0 decision record lives in meta issue #898. These are the entries this operator implements.

  • D2 (operator split): a separate ovn-operator with the kinds OVNCentral and OVNChassis, beside a neutron-operator that owns the Neutron kind. The coupling is CR status alone: this operator watches OVNCentral and reads the addresses it publishes, which keeps the OVN layer available to a later consumer. D7 added the second kind on this side of the split.
  • D5 (RabbitMQ scope): the shared bus from #895, with quorum queues and stable queue names, transport_url delivered by environment override only, and the notifications driver at noop.
  • D7 (metadata agent): neutron-ovn-metadata-agent as a DaemonSet on the compute nodes, projected by this operator rather than by the ovn-operator, because this operator is the one that renders neutron_ovn_metadata_agent.ini. It carries a same-node startup gate on chassis readiness, expressed as an init container that reads the node's system-id from the local ovsdb socket and waits until the Southbound database holds the Chassis_Private row of that name. See Node contract.
  • D10 (neutron-server launch mode): one launch mode for the API on every release. neutron/wsgi/api.py is byte-identical at 27.0.3 and 28.0.1, 29.0.0 adds prog='neutron-api' to the boot_server call, and no release ships a neutron-server binary, so the API is uwsgi … --module neutron.wsgi.api. Configuration travels in OS_NEUTRON_CONFIG_DIR and OS_NEUTRON_CONFIG_FILES, since --config-dir alone fails with ConfigFilesNotFoundError. --set-placeholder start-time=%t must not be rendered on the command line: uWSGI passes the literal %t and neutron dies on int('%t'). The operator writes start-time = %t into a uwsgi.ini instead, where uWSGI expands it while reading the file.
  • D11 (minimal RPC-worker posture): the process inventory above and the bus posture above. The contrast run with the two worker keys removed cost one AMQP connection, one channel, four durable quorum queues and three exchanges, and those queues outlive the process that declared them.

BGP is out of scope here and tracked in its own meta, #899.

Owned resources ​

The figure under Owned Resources of the Keystone operator draws the baseline this list follows: serving objects, config and Secrets, Jobs and CronJobs.

For a Neutron named {name} the operator manages:

ResourceNamePurpose
Deployment{name}The API pods, uWSGI on port 9696
Service{name}ClusterIP in front of the API pods on port 9696
PodDisruptionBudget{name}minAvailable: 1 above a lower replica bound of one, maxUnavailable: 1 at one (the bound is the HPA's minReplicas while spec.autoscaling is set); selects the API component only
HorizontalPodAutoscaler{name}Only while spec.autoscaling is set; the workers are never autoscaled
NetworkPolicy{name}Only while spec.networkPolicy is set
HTTPRoute{name}Only while spec.gateway is set
MariaDB Database / User / Grant{name}Managed mode only (spec.database.clusterRef); a brownfield database is left alone
Deployment{name}-periodic-workersneutron-periodic-workers
Deployment{name}-ovn-maintenance-workerneutron-ovn-maintenance-worker
ConfigMap{name}-config-<hash>Immutable, content-addressed neutron.conf, ml2_conf.ini and uwsgi.ini, plus logging.conf for json logging; 3 historical retained
Secret{name}-db-connectionThe derived pymysql DSN, consumed through OS_DATABASE__CONNECTION
Secret{name}-transport-urlThe derived rabbit:// URL, consumed through OS_DEFAULT__TRANSPORT_URL
Secret{name}-ovn-clientThe mirror of the client identity the OVNCentral publishes: tls.crt, tls.key, ca.crt
Job{name}-db-syncneutron-db-manage upgrade head
Job{name}-db-expand, {name}-db-migrate, {name}-db-contractThe three release-upgrade phases
CronJob{name}-ovn-db-syncneutron-ovn-db-sync-util, only while spec.ovnDBSync is set

For a NeutronMetadataAgent named {name}:

ResourceNamePurpose
DaemonSet{name}-metadata-agentThe agent pods on the nodes the referenced OVNChassis selects
ConfigMap{name}-config-<hash>Immutable, content-addressed neutron_ovn_metadata_agent.ini, plus logging.conf for json logging; 3 historical retained
Secret{name}-transport-urlThe derived rabbit:// URL, written only while spec.messaging is set

The client Secret the agent pods mount is not in that list. cert-manager issues it and the OVNCentral publishes it; this operator reads its name off the central and mounts it.

Reference pages ​

A ControlPlane projects the Neutron child from ServiceNeutronSpec, which derives the database, the cache, the Keystone endpoint and the bus from the plane and leaves the rest to that spec. The OVN layer this operator programs is documented under OVN Operator.