feat: Neutron OVS+uwsgi support (#1160)

relate to #42
Note: ovn can't properly use uWSGI for now due to: https://bugs.launchpad.net/neutron/+bug/1912359

Reviewed-by: Mohammed Naser <mnaser@vexxhost.com>
diff --git a/.charts.yml b/.charts.yml
index 2b0c887..5887972 100644
--- a/.charts.yml
+++ b/.charts.yml
@@ -127,14 +127,13 @@
     repository: *openstack_helm_infra_repository
     dependencies: *openstack_helm_dependencies
   - name: neutron
-    version: 0.3.29
+    version: 0.3.41
     repository: *openstack_helm_repository
     dependencies: *openstack_helm_dependencies
     patches:
       gerrit:
         review.opendev.org:
-          - 902767
-          - 914886
+          - 916862
   - name: node-feature-discovery
     version: 0.15.4
     repository:
diff --git a/charts/neutron/Chart.yaml b/charts/neutron/Chart.yaml
index d230623..5e829ae 100644
--- a/charts/neutron/Chart.yaml
+++ b/charts/neutron/Chart.yaml
@@ -9,4 +9,4 @@
 sources:
 - https://opendev.org/openstack/neutron
 - https://opendev.org/openstack/openstack-helm
-version: 0.3.29
+version: 0.3.41
diff --git a/charts/neutron/templates/bin/_health-probe.py.tpl b/charts/neutron/templates/bin/_health-probe.py.tpl
index 897b735..b5e170b 100644
--- a/charts/neutron/templates/bin/_health-probe.py.tpl
+++ b/charts/neutron/templates/bin/_health-probe.py.tpl
@@ -315,16 +315,20 @@
     data = {}
     if os.path.isfile(pidfile):
         with open(pidfile,'r') as f:
-            data = json.load(f)
-        if check_pid_running(data['pid']):
-            if data['exit_count'] > 1:
-                # Third time in, kill the previous process
-                os.kill(int(data['pid']), signal.SIGTERM)
-            else:
-                data['exit_count'] = data['exit_count'] + 1
-                with open(pidfile, 'w') as f:
-                    json.dump(data, f)
-                sys.exit(0)
+            file_content = f.read().strip()
+            if file_content:
+                data = json.loads(file_content)
+
+    if 'pid' in data and check_pid_running(data['pid']):
+        if 'exit_count' in data and data['exit_count'] > 1:
+            # Third time in, kill the previous process
+            os.kill(int(data['pid']), signal.SIGTERM)
+        else:
+            data['exit_count'] = data.get('exit_count', 0) + 1
+            with open(pidfile, 'w') as f:
+                json.dump(data, f)
+            sys.exit(0)
+
     data['pid'] = os.getpid()
     data['exit_count'] = 0
     with open(pidfile, 'w') as f:
diff --git a/charts/neutron/templates/bin/_neutron-openvswitch-agent-init.sh.tpl b/charts/neutron/templates/bin/_neutron-openvswitch-agent-init.sh.tpl
index 883b71a..bd0a64a 100644
--- a/charts/neutron/templates/bin/_neutron-openvswitch-agent-init.sh.tpl
+++ b/charts/neutron/templates/bin/_neutron-openvswitch-agent-init.sh.tpl
@@ -174,6 +174,21 @@
   fi
 }
 
+function ensure_vf_state {
+  iface=${1}
+  vf_string=${2}
+  check_string=${3}
+  expected=${4}
+
+  # wait for the vf really get the needed state
+  for i in 0 1 2 4 8 16 32; do
+    sleep ${i};
+    if [ "$(ip link show ${iface} | grep "${vf_string} " | grep -Eo "${check_string}")" == "${expected}" ]; then
+      break;
+    fi;
+  done
+}
+
 function process_dpdk_nics {
   target_driver=$(get_dpdk_config_value ${DPDK_CONFIG} '.driver')
   # loop over all nics
@@ -195,11 +210,14 @@
       if [ -n "${vf_index}" ]; then
         vf_string="vf ${vf_index}"
         ip link set ${iface} ${vf_string} trust on
+        ensure_vf_state "${iface}" "${vf_string}" "trust o(n|ff)" "trust on"
 
         # NOTE: To ensure proper toggle of spoofchk,
         # turn it on then off.
         ip link set ${iface} ${vf_string} spoofchk on
+        ensure_vf_state "${iface}" "${vf_string}" "spoof checking o(n|ff)" "spoof checking on"
         ip link set ${iface} ${vf_string} spoofchk off
+        ensure_vf_state "${iface}" "${vf_string}" "spoof checking o(n|ff)" "spoof checking off"
       fi
     fi
 
@@ -291,11 +309,14 @@
         if [ -n "${vf_index}" ]; then
           vf_string="vf ${vf_index}"
           ip link set ${iface} ${vf_string} trust on
+          ensure_vf_state "${iface}" "${vf_string}" "trust o(n|ff)" "trust on"
 
           # NOTE: To ensure proper toggle of spoofchk,
           # turn it on then off.
           ip link set ${iface} ${vf_string} spoofchk on
+          ensure_vf_state "${iface}" "${vf_string}" "spoof checking o(n|ff)" "spoof checking on"
           ip link set ${iface} ${vf_string} spoofchk off
+          ensure_vf_state "${iface}" "${vf_string}" "spoof checking o(n|ff)" "spoof checking off"
         fi
       fi
 
@@ -406,12 +427,16 @@
 do
   bridge=${bmap%:*}
   iface=${bmap#*:}
-  ovs-vsctl --no-wait --may-exist add-br $bridge
-  if [ -n "$iface" ] && [ "$iface" != "null" ]
+  if [[ "${DPDK_ENABLED}" == "true" ]]; then
+    ovs-vsctl --db=unix:${OVS_SOCKET} --may-exist add-br $bridge -- set bridge $bridge datapath_type=netdev
+  else
+    ovs-vsctl --db=unix:${OVS_SOCKET} --may-exist add-br $bridge
+  fi
+  if [ -n "$iface" ] && [ "$iface" != "null" ] && ( ip link show $iface 1>/dev/null 2>&1 );
   then
-    ovs-vsctl --no-wait --may-exist add-port $bridge $iface
+    ovs-vsctl --db=unix:${OVS_SOCKET} --may-exist add-port $bridge $iface
     migrate_ip_from_nic $iface $bridge
-    if [[ $(get_dpdk_config_value ${DPDK_CONFIG} '.enabled') != "true" ]]; then
+    if [[ "${DPDK_ENABLED}" != "true" ]]; then
       ip link set dev $iface up
     fi
   fi
diff --git a/charts/neutron/templates/bin/_neutron-rpc-server.sh.tpl b/charts/neutron/templates/bin/_neutron-rpc-server.sh.tpl
new file mode 100644
index 0000000..b20d04e
--- /dev/null
+++ b/charts/neutron/templates/bin/_neutron-rpc-server.sh.tpl
@@ -0,0 +1,46 @@
+#!/bin/bash
+
+{{/*
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/}}
+
+set -ex
+COMMAND="${@:-start}"
+
+function start () {
+  exec neutron-rpc-server \
+        --config-file /etc/neutron/neutron.conf \
+{{- if ( has "ovn" .Values.network.backend ) }}
+        --config-file /tmp/pod-shared/ovn.ini \
+{{- end }}
+{{- if .Values.conf.plugins.taas.taas.enabled }}
+        --config-file /etc/neutron/taas_plugin.ini \
+{{- end }}
+{{- if ( has "sriov" .Values.network.backend ) }}
+        --config-file /etc/neutron/plugins/ml2/sriov_agent.ini \
+{{- end }}
+{{- if .Values.conf.plugins.l2gateway }}
+        --config-file /etc/neutron/l2gw_plugin.ini \
+{{- end }}
+{{- if ( has "tungstenfabric" .Values.network.backend ) }}
+        --config-file /etc/neutron/plugins/tungstenfabric/tf_plugin.ini
+{{- else }}
+        --config-file /etc/neutron/plugins/ml2/ml2_conf.ini
+{{- end }}
+}
+
+function stop () {
+  kill -TERM 1
+}
+
+$COMMAND
diff --git a/charts/neutron/templates/bin/_neutron-server.sh.tpl b/charts/neutron/templates/bin/_neutron-server.sh.tpl
index 8cbb688..be4b254 100644
--- a/charts/neutron/templates/bin/_neutron-server.sh.tpl
+++ b/charts/neutron/templates/bin/_neutron-server.sh.tpl
@@ -18,6 +18,17 @@
 COMMAND="${@:-start}"
 
 function start () {
+# (ricolin): Currently ovn have issue with uWSGI,
+# let's keep using non-uWSGI way until this bug fixed:
+# https://bugs.launchpad.net/neutron/+bug/1912359
+{{- if ( has "ovn" .Values.network.backend ) }}
+  start_ovn
+{{- else }}
+  exec uwsgi --ini /etc/neutron/neutron-api-uwsgi.ini
+{{- end }}
+}
+
+function start_ovn () {
   exec neutron-server \
         --config-file /etc/neutron/neutron.conf \
 {{- if ( has "ovn" .Values.network.backend ) }}
diff --git a/charts/neutron/templates/configmap-bin.yaml b/charts/neutron/templates/configmap-bin.yaml
index 9a934e0..40b7006 100644
--- a/charts/neutron/templates/configmap-bin.yaml
+++ b/charts/neutron/templates/configmap-bin.yaml
@@ -91,6 +91,8 @@
 {{- end }}
   neutron-server.sh: |
 {{ tuple "bin/_neutron-server.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+  neutron-rpc-server.sh: |
+{{ tuple "bin/_neutron-rpc-server.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
   neutron-ironic-agent.sh: |
 {{ tuple "bin/_neutron-ironic-agent.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
   neutron-netns-cleanup-cron.sh: |
diff --git a/charts/neutron/templates/configmap-etc.yaml b/charts/neutron/templates/configmap-etc.yaml
index 88fea72..f7411bf 100644
--- a/charts/neutron/templates/configmap-etc.yaml
+++ b/charts/neutron/templates/configmap-etc.yaml
@@ -120,18 +120,11 @@
 {{- $_ := tuple "load_balancer" "internal" "api" . | include "helm-toolkit.endpoints.keystone_endpoint_uri_lookup"| set $envAll.Values.conf.neutron.octavia "base_url" -}}
 {{- end }}
 
-{{/*
-nova_metadata_ip can go away when Newton is no longer supported, otherwise
-just set it along with nova_metadata_host.
-*/}}
-{{- if empty $envAll.Values.conf.metadata_agent.DEFAULT.nova_metadata_ip -}}
-{{- $_ := tuple "compute_metadata" "public" . | include "helm-toolkit.endpoints.hostname_fqdn_endpoint_lookup" | set $envAll.Values.conf.metadata_agent.DEFAULT "nova_metadata_ip" -}}
-{{- end -}}
 {{- if empty $envAll.Values.conf.metadata_agent.DEFAULT.nova_metadata_host -}}
-{{- $_ := tuple "compute_metadata" "public" . | include "helm-toolkit.endpoints.hostname_fqdn_endpoint_lookup" | set $envAll.Values.conf.metadata_agent.DEFAULT "nova_metadata_host" -}}
+{{- $_ := tuple "compute_metadata" "internal" . | include "helm-toolkit.endpoints.hostname_fqdn_endpoint_lookup" | set $envAll.Values.conf.metadata_agent.DEFAULT "nova_metadata_host" -}}
 {{- end -}}
 {{- if empty $envAll.Values.conf.metadata_agent.DEFAULT.nova_metadata_port -}}
-{{- $_ := set $envAll.Values.conf.metadata_agent.DEFAULT "nova_metadata_port" 80 -}}
+{{- $_ := tuple "compute_metadata" "internal" "metadata" . | include "helm-toolkit.endpoints.endpoint_port_lookup" | set $envAll.Values.conf.metadata_agent.DEFAULT "nova_metadata_port" }}
 {{- end -}}
 {{- if empty $envAll.Values.conf.metadata_agent.cache.memcache_servers -}}
 {{- $_ := tuple "oslo_cache" "internal" "memcache" . | include "helm-toolkit.endpoints.host_and_port_endpoint_uri_lookup" | set $envAll.Values.conf.metadata_agent.cache "memcache_servers" -}}
@@ -196,6 +189,14 @@
 {{- if empty .Values.conf.neutron.DEFAULT.bind_port -}}
 {{- $_ := tuple "network" "service" "api" . | include "helm-toolkit.endpoints.endpoint_port_lookup" | set .Values.conf.neutron.DEFAULT "bind_port" -}}
 {{- end -}}
+{{- if empty .Values.conf.neutron_api_uwsgi.uwsgi.processes -}}
+{{- $_ := set .Values.conf.neutron_api_uwsgi.uwsgi "processes" .Values.conf.neutron.DEFAULT.api_workers -}}
+{{- end -}}
+{{- if empty (index .Values.conf.neutron_api_uwsgi.uwsgi "http-socket") -}}
+{{- $http_socket_port := tuple "network" "service" "api" . | include "helm-toolkit.endpoints.endpoint_port_lookup" | toString }}
+{{- $http_socket := printf "0.0.0.0:%s" $http_socket_port }}
+{{- $_ := set .Values.conf.neutron_api_uwsgi.uwsgi "http-socket" $http_socket -}}
+{{- end -}}
 
 {{- if and (empty .Values.conf.logging.handler_fluent) (has "fluent" .Values.conf.logging.handlers.keys) -}}
 {{- $fluentd_host := tuple "fluentd" "internal" $envAll | include "helm-toolkit.endpoints.hostname_namespaced_endpoint_lookup" }}
@@ -291,6 +292,7 @@
   rally_tests.yaml: {{ toYaml $envAll.Values.conf.rally_tests.tests | b64enc }}
   api-paste.ini: {{ include "helm-toolkit.utils.to_ini" $envAll.Values.conf.paste | b64enc }}
   policy.yaml: {{ toYaml $envAll.Values.conf.policy | b64enc }}
+  neutron-api-uwsgi.ini: {{ include "helm-toolkit.utils.to_oslo_conf" .Values.conf.neutron_api_uwsgi | b64enc }}
   neutron.conf: {{ include "helm-toolkit.utils.to_oslo_conf" $envAll.Values.conf.neutron | b64enc }}
   logging.conf: {{ include "helm-toolkit.utils.to_oslo_conf" .Values.conf.logging | b64enc }}
   api_audit_map.conf: {{ include "helm-toolkit.utils.to_oslo_conf" .Values.conf.api_audit_map | b64enc }}
diff --git a/charts/neutron/templates/daemonset-bagpipe-bgp.yaml b/charts/neutron/templates/daemonset-bagpipe-bgp.yaml
index 9e6393e..b6d2157 100644
--- a/charts/neutron/templates/daemonset-bagpipe-bgp.yaml
+++ b/charts/neutron/templates/daemonset-bagpipe-bgp.yaml
@@ -54,6 +54,7 @@
 {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
         configmap-bin-hash: {{ tuple "configmap-bin.yaml" . | include "helm-toolkit.utils.hash" }}
         configmap-etc-hash: {{ tuple "configmap-etc.yaml" . | include "helm-toolkit.utils.hash" }}
+{{ tuple "neutron_bagpipe_bgp" . | include "helm-toolkit.snippets.custom_pod_annotations" | indent 8 }}
     spec:
 {{ dict "envAll" $envAll "application" "neutron_bagpipe_bgp" | include "helm-toolkit.snippets.kubernetes_pod_security_context" | indent 6 }}
       serviceAccountName: {{ $serviceAccountName }}
diff --git a/charts/neutron/templates/daemonset-bgp-dragent.yaml b/charts/neutron/templates/daemonset-bgp-dragent.yaml
index ca8a3d1..b0494c3 100644
--- a/charts/neutron/templates/daemonset-bgp-dragent.yaml
+++ b/charts/neutron/templates/daemonset-bgp-dragent.yaml
@@ -53,6 +53,7 @@
 {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
         configmap-bin-hash: {{ tuple "configmap-bin.yaml" . | include "helm-toolkit.utils.hash" }}
         configmap-etc-hash: {{ tuple "configmap-etc.yaml" . | include "helm-toolkit.utils.hash" }}
+{{ tuple "neutron_bgp_dragent" . | include "helm-toolkit.snippets.custom_pod_annotations" | indent 8 }}
     spec:
 {{ dict "envAll" $envAll "application" "neutron_bgp_dragent" | include "helm-toolkit.snippets.kubernetes_pod_security_context" | indent 6 }}
       serviceAccountName: {{ $serviceAccountName }}
diff --git a/charts/neutron/templates/daemonset-dhcp-agent.yaml b/charts/neutron/templates/daemonset-dhcp-agent.yaml
index f2a5a85..17e15f8 100644
--- a/charts/neutron/templates/daemonset-dhcp-agent.yaml
+++ b/charts/neutron/templates/daemonset-dhcp-agent.yaml
@@ -75,6 +75,7 @@
 {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
         configmap-bin-hash: {{ tuple "configmap-bin.yaml" . | include "helm-toolkit.utils.hash" }}
         configmap-etc-hash: {{ tuple "configmap-etc.yaml" . | include "helm-toolkit.utils.hash" }}
+{{ tuple "neutron_dhcp_agent" . | include "helm-toolkit.snippets.custom_pod_annotations" | indent 8 }}
 {{ dict "envAll" $envAll "podName" "neutron-dhcp-agent-default" "containerNames" (list "neutron-dhcp-agent" "neutron-dhcp-agent-init" "init") | include "helm-toolkit.snippets.kubernetes_mandatory_access_control_annotation" | indent 8 }}
     spec:
 {{ dict "envAll" $envAll "application" "neutron_dhcp_agent" | include "helm-toolkit.snippets.kubernetes_pod_security_context" | indent 6 }}
diff --git a/charts/neutron/templates/daemonset-l2gw-agent.yaml b/charts/neutron/templates/daemonset-l2gw-agent.yaml
index 2bb2fdc..e948198 100644
--- a/charts/neutron/templates/daemonset-l2gw-agent.yaml
+++ b/charts/neutron/templates/daemonset-l2gw-agent.yaml
@@ -77,6 +77,7 @@
 {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
         configmap-bin-hash: {{ tuple "configmap-bin.yaml" . | include "helm-toolkit.utils.hash" }}
         configmap-etc-hash: {{ tuple "configmap-etc.yaml" . | include "helm-toolkit.utils.hash" }}
+{{ tuple "neutron_l2gw_agent" . | include "helm-toolkit.snippets.custom_pod_annotations" | indent 8 }}
     spec:
 {{ dict "envAll" $envAll "application" "neutron_l2gw_agent" | include "helm-toolkit.snippets.kubernetes_pod_security_context" | indent 6 }}
       serviceAccountName: {{ $serviceAccountName }}
diff --git a/charts/neutron/templates/daemonset-l3-agent.yaml b/charts/neutron/templates/daemonset-l3-agent.yaml
index 65cfe09..b4bbd09 100644
--- a/charts/neutron/templates/daemonset-l3-agent.yaml
+++ b/charts/neutron/templates/daemonset-l3-agent.yaml
@@ -76,6 +76,7 @@
 {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
         configmap-bin-hash: {{ tuple "configmap-bin.yaml" . | include "helm-toolkit.utils.hash" }}
         configmap-etc-hash: {{ tuple "configmap-etc.yaml" . | include "helm-toolkit.utils.hash" }}
+{{ tuple "neutron_l3_agent" . | include "helm-toolkit.snippets.custom_pod_annotations" | indent 8 }}
 {{ dict "envAll" $envAll "podName" "neutron-l3-agent-default" "containerNames" (list "neutron-l3-agent" "init"  "neutron-l3-agent-init") | include "helm-toolkit.snippets.kubernetes_mandatory_access_control_annotation" | indent 8 }}
     spec:
 {{ dict "envAll" $envAll "application" "neutron_l3_agent" | include "helm-toolkit.snippets.kubernetes_pod_security_context" | indent 6 }}
diff --git a/charts/neutron/templates/daemonset-lb-agent.yaml b/charts/neutron/templates/daemonset-lb-agent.yaml
index 7cb8637..35ff8fe 100644
--- a/charts/neutron/templates/daemonset-lb-agent.yaml
+++ b/charts/neutron/templates/daemonset-lb-agent.yaml
@@ -52,6 +52,7 @@
 {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
         configmap-bin-hash: {{ tuple "configmap-bin.yaml" . | include "helm-toolkit.utils.hash" }}
         configmap-etc-hash: {{ tuple "configmap-etc.yaml" . | include "helm-toolkit.utils.hash" }}
+{{ tuple "neutron_lb_agent" . | include "helm-toolkit.snippets.custom_pod_annotations" | indent 8 }}
     spec:
 {{ dict "envAll" $envAll "application" "neutron_lb_agent" | include "helm-toolkit.snippets.kubernetes_pod_security_context" | indent 6 }}
       serviceAccountName: {{ $serviceAccountName }}
diff --git a/charts/neutron/templates/daemonset-metadata-agent.yaml b/charts/neutron/templates/daemonset-metadata-agent.yaml
index edfa0a1..fc9a75e 100644
--- a/charts/neutron/templates/daemonset-metadata-agent.yaml
+++ b/charts/neutron/templates/daemonset-metadata-agent.yaml
@@ -72,6 +72,7 @@
 {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
         configmap-bin-hash: {{ tuple "configmap-bin.yaml" . | include "helm-toolkit.utils.hash" }}
         configmap-etc-hash: {{ tuple "configmap-etc.yaml" . | include "helm-toolkit.utils.hash" }}
+{{ tuple "neutron_metadata_agent" . | include "helm-toolkit.snippets.custom_pod_annotations" | indent 8 }}
 {{ dict "envAll" $envAll "podName" "neutron-metadata-agent-default" "containerNames" (list "neutron-metadata-agent" "neutron-metadata-agent-init" "init") | include "helm-toolkit.snippets.kubernetes_mandatory_access_control_annotation" | indent 8 }}
     spec:
 {{ dict "envAll" $envAll "application" "neutron_metadata_agent" | include "helm-toolkit.snippets.kubernetes_pod_security_context" | indent 6 }}
diff --git a/charts/neutron/templates/daemonset-netns-cleanup-cron.yaml b/charts/neutron/templates/daemonset-netns-cleanup-cron.yaml
index 4688cdf..d43c595 100644
--- a/charts/neutron/templates/daemonset-netns-cleanup-cron.yaml
+++ b/charts/neutron/templates/daemonset-netns-cleanup-cron.yaml
@@ -44,6 +44,7 @@
 {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
         configmap-bin-hash: {{ tuple "configmap-bin.yaml" . | include "helm-toolkit.utils.hash" }}
         configmap-etc-hash: {{ tuple "configmap-etc.yaml" . | include "helm-toolkit.utils.hash" }}
+{{ tuple "neutron_netns_cleanup_cron" . | include "helm-toolkit.snippets.custom_pod_annotations" | indent 8 }}
 {{ dict "envAll" $envAll "podName" "neutron-netns-cleanup-cron-default" "containerNames" (list "neutron-netns-cleanup-cron" "init" ) | include "helm-toolkit.snippets.kubernetes_mandatory_access_control_annotation" | indent 8 }}
     spec:
 {{ dict "envAll" $envAll "application" "neutron_netns_cleanup_cron" | include "helm-toolkit.snippets.kubernetes_pod_security_context" | indent 6 }}
diff --git a/charts/neutron/templates/daemonset-ovn-metadata-agent.yaml b/charts/neutron/templates/daemonset-ovn-metadata-agent.yaml
index 5c2999c..47e1256 100644
--- a/charts/neutron/templates/daemonset-ovn-metadata-agent.yaml
+++ b/charts/neutron/templates/daemonset-ovn-metadata-agent.yaml
@@ -72,6 +72,7 @@
 {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
         configmap-bin-hash: {{ tuple "configmap-bin.yaml" . | include "helm-toolkit.utils.hash" }}
         configmap-etc-hash: {{ tuple "configmap-etc.yaml" . | include "helm-toolkit.utils.hash" }}
+{{ tuple "neutron_ovn_metadata_agent" . | include "helm-toolkit.snippets.custom_pod_annotations" | indent 8 }}
 {{ dict "envAll" $envAll "podName" "neutron-ovn-metadata-agent-default" "containerNames" (list "neutron-ovn-metadata-agent" "neutron-ovn-metadata-agent-init" "init") | include "helm-toolkit.snippets.kubernetes_mandatory_access_control_annotation" | indent 8 }}
     spec:
 {{ dict "envAll" $envAll "application" "neutron_ovn_metadata_agent" | include "helm-toolkit.snippets.kubernetes_pod_security_context" | indent 6 }}
@@ -143,8 +144,8 @@
           command:
             - /tmp/neutron-ovn-metadata-agent.sh
           volumeMounts:
-            - name: run
-              mountPath: /run
+            - name: run-openvswitch
+              mountPath: /run/openvswitch
             - name: pod-tmp
               mountPath: /tmp
             - name: pod-var-neutron
@@ -217,9 +218,6 @@
           emptyDir: {}
         - name: pod-var-neutron
           emptyDir: {}
-        - name: run
-          hostPath:
-            path: /run
         - name: run-openvswitch
           hostPath:
             path: /run/openvswitch
diff --git a/charts/neutron/templates/daemonset-ovs-agent.yaml b/charts/neutron/templates/daemonset-ovs-agent.yaml
index 82bbd36..0ea60f5 100644
--- a/charts/neutron/templates/daemonset-ovs-agent.yaml
+++ b/charts/neutron/templates/daemonset-ovs-agent.yaml
@@ -55,6 +55,7 @@
 {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
         configmap-bin-hash: {{ tuple "configmap-bin.yaml" . | include "helm-toolkit.utils.hash" }}
         configmap-etc-hash: {{ tuple "configmap-etc.yaml" . | include "helm-toolkit.utils.hash" }}
+{{ tuple "neutron_ovs_agent" . | include "helm-toolkit.snippets.custom_pod_annotations" | indent 8 }}
 {{ dict "envAll" $envAll "podName" "$configMapName" "containerNames" (list "neutron-ovs-agent" "init" "neutron-openvswitch-agent-kernel-modules" "neutron-ovs-agent-init") | include "helm-toolkit.snippets.kubernetes_mandatory_access_control_annotation" | indent 8 }}
     spec:
 {{ dict "envAll" $envAll "application" "neutron_ovs_agent" | include "helm-toolkit.snippets.kubernetes_pod_security_context" | indent 6 }}
diff --git a/charts/neutron/templates/daemonset-sriov-agent.yaml b/charts/neutron/templates/daemonset-sriov-agent.yaml
index 4bf0021..5b96cd7 100644
--- a/charts/neutron/templates/daemonset-sriov-agent.yaml
+++ b/charts/neutron/templates/daemonset-sriov-agent.yaml
@@ -58,6 +58,7 @@
 {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
         configmap-bin-hash: {{ tuple "configmap-bin.yaml" . | include "helm-toolkit.utils.hash" }}
         configmap-etc-hash: {{ tuple "configmap-etc.yaml" . | include "helm-toolkit.utils.hash" }}
+{{ tuple "neutron_sriov_agent" . | include "helm-toolkit.snippets.custom_pod_annotations" | indent 8 }}
 {{ dict "envAll" $envAll "podName" "neutron-sriov-agent-default" "containerNames" (list "neutron-sriov-agent-init" "init" "neutron-sriov-agent") | include "helm-toolkit.snippets.kubernetes_mandatory_access_control_annotation" | indent 8 }}
     spec:
 {{ dict "envAll" $envAll "application" "neutron_sriov_agent" | include "helm-toolkit.snippets.kubernetes_pod_security_context" | indent 6 }}
diff --git a/charts/neutron/templates/deployment-ironic-agent.yaml b/charts/neutron/templates/deployment-ironic-agent.yaml
index 431225f..014c9ad 100644
--- a/charts/neutron/templates/deployment-ironic-agent.yaml
+++ b/charts/neutron/templates/deployment-ironic-agent.yaml
@@ -46,6 +46,7 @@
 {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
         configmap-bin-hash: {{ tuple "configmap-bin.yaml" . | include "helm-toolkit.utils.hash" }}
         configmap-etc-hash: {{ tuple "configmap-etc.yaml" . | include "helm-toolkit.utils.hash" }}
+{{ tuple "neutron_ironic_agent" . | include "helm-toolkit.snippets.custom_pod_annotations" | indent 8 }}
     spec:
 {{ dict "envAll" $envAll "application" "neutron_ironic_agent" | include "helm-toolkit.snippets.kubernetes_pod_security_context" | indent 6 }}
       serviceAccountName: {{ $serviceAccountName }}
diff --git a/charts/neutron/templates/deployment-rpc_server.yaml b/charts/neutron/templates/deployment-rpc_server.yaml
new file mode 100644
index 0000000..1866e21
--- /dev/null
+++ b/charts/neutron/templates/deployment-rpc_server.yaml
@@ -0,0 +1,227 @@
+{{/*
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/}}
+
+{{- if .Values.manifests.deployment_rpc_server }}
+{{- $envAll := . }}
+
+{{- $dependencyOpts := dict "envAll" $envAll "dependencyMixinParam" $envAll.Values.network.backend "dependencyKey" "server" -}}
+{{- $_ := include "helm-toolkit.utils.dependency_resolver" $dependencyOpts | toString | fromYaml }}
+
+{{- $mounts_neutron_rpc_server := .Values.pod.mounts.neutron_rpc_server.neutron_rpc_server }}
+{{- $mounts_neutron_rpc_server_init := .Values.pod.mounts.neutron_rpc_server.init_container }}
+
+{{- $serviceAccountName := "neutron-rpc-server" }}
+{{ tuple $envAll "pod_dependency" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: neutron-rpc-server
+  annotations:
+    {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" }}
+  labels:
+{{ tuple $envAll "neutron" "rpc_server" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+spec:
+  replicas: {{ .Values.pod.replicas.rpc_server }}
+  selector:
+    matchLabels:
+{{ tuple $envAll "neutron" "rpc_server" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 6 }}
+{{ tuple $envAll | include "helm-toolkit.snippets.kubernetes_upgrades_deployment" | indent 2 }}
+  template:
+    metadata:
+      labels:
+{{ tuple $envAll "neutron" "rpc_server" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
+      annotations:
+{{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
+        configmap-bin-hash: {{ tuple "configmap-bin.yaml" . | include "helm-toolkit.utils.hash" }}
+        configmap-etc-hash: {{ tuple "configmap-etc.yaml" . | include "helm-toolkit.utils.hash" }}
+{{ dict "envAll" $envAll "podName" "neutron-rpc-server" "containerNames" (list "neutron-rpc-server" "init") | include "helm-toolkit.snippets.kubernetes_mandatory_access_control_annotation" | indent 8 }}
+    spec:
+{{ dict "envAll" $envAll "application" "neutron_rpc_server" | include "helm-toolkit.snippets.kubernetes_pod_security_context" | indent 6 }}
+      serviceAccountName: {{ $serviceAccountName }}
+      affinity:
+{{ tuple $envAll "neutron" "rpc_server" | include "helm-toolkit.snippets.kubernetes_pod_anti_affinity" | indent 8 }}
+      nodeSelector:
+        {{ .Values.labels.rpc_server.node_selector_key }}: {{ .Values.labels.rpc_server.node_selector_value }}
+{{ if $envAll.Values.pod.tolerations.neutron.enabled }}
+{{ tuple $envAll "neutron" | include "helm-toolkit.snippets.kubernetes_tolerations" | indent 6 }}
+{{ end }}
+      terminationGracePeriodSeconds: {{ .Values.pod.lifecycle.termination_grace_period.rpc_server.timeout | default "30" }}
+      initContainers:
+{{ tuple $envAll "pod_dependency" $mounts_neutron_rpc_server_init | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }}
+        {{- if ( has "ovn" .Values.network.backend ) }}
+        - name: ovn-neutron-init
+{{ tuple $envAll "neutron_rpc_server" | include "helm-toolkit.snippets.image" | indent 10 }}
+          command:
+            - /tmp/neutron-ovn-init.sh
+          volumeMounts:
+            - name: pod-shared
+              mountPath: /tmp/pod-shared
+            - name: neutron-bin
+              mountPath: /tmp/neutron-ovn-init.sh
+              subPath: neutron-ovn-init.sh
+              readOnly: true
+        {{- end }}
+        {{- if ( has "tungstenfabric" .Values.network.backend ) }}
+        - name: tungstenfabric-neutron-init
+          image: {{ .Values.images.tags.tf_neutron_init }}
+          imagePullPolicy: {{ .Values.images.pull_policy }}
+{{ tuple $envAll $envAll.Values.pod.resources.rpc_server | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+          securityContext:
+            runAsUser: {{ .Values.pod.security_context.neutron_rpc_server.pod.runAsUser }}
+          env:
+            - name: OPENSTACK_VERSION
+              value: "{{ .Values.conf.openstack_version }}"
+          volumeMounts:
+            - name: neutron-plugin-shared
+              mountPath: /opt/plugin
+        {{- end }}
+      containers:
+        - name: neutron-rpc-server
+{{ tuple $envAll "neutron_rpc_server" | include "helm-toolkit.snippets.image" | indent 10 }}
+{{ tuple $envAll $envAll.Values.pod.resources.rpc_server | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+{{ dict "envAll" $envAll "application" "neutron_rpc_server" "container" "neutron_rpc_server" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+          command:
+            - /tmp/neutron-rpc-server.sh
+            - start
+{{- if or .Values.manifests.certificates .Values.tls.identity }}
+          env:
+            - name: REQUESTS_CA_BUNDLE
+              value: "/etc/neutron/certs/ca.crt"
+{{- end }}
+          lifecycle:
+            preStop:
+              exec:
+                command:
+                  - /tmp/neutron-rpc-server.sh
+                  - stop
+          ports:
+            - name: q-api
+              containerPort: {{ tuple "network" "service" "api" . | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: pod-shared
+              mountPath: /tmp/pod-shared
+            - name: pod-var-neutron
+              mountPath: {{ .Values.conf.neutron.DEFAULT.state_path }}
+            - name: neutron-bin
+              mountPath: /tmp/neutron-rpc-server.sh
+              subPath: neutron-rpc-server.sh
+              readOnly: true
+            - name: neutron-etc
+              mountPath: /etc/neutron/neutron.conf
+              subPath: neutron.conf
+              readOnly: true
+            - name: neutron-etc
+              mountPath: /etc/neutron/neutron-api-uwsgi.ini
+              subPath: neutron-api-uwsgi.ini
+              readOnly: true
+            {{- if .Values.conf.neutron.DEFAULT.log_config_append }}
+            - name: neutron-etc
+              mountPath: {{ .Values.conf.neutron.DEFAULT.log_config_append }}
+              subPath: {{ base .Values.conf.neutron.DEFAULT.log_config_append }}
+              readOnly: true
+            {{- end }}
+            - name: neutron-etc
+              mountPath: /etc/neutron/api_audit_map.conf
+              subPath: api_audit_map.conf
+              readOnly: true
+            {{- if( has "tungstenfabric" .Values.network.backend ) }}
+            - name: neutron-etc
+              mountPath: /etc/neutron/plugins/tungstenfabric/tf_plugin.ini
+              subPath: tf_plugin.ini
+              readOnly: true
+            - name: neutron-etc
+              mountPath: /etc/contrail/vnc_api_lib.ini
+              subPath: vnc_api_lib.ini
+              readOnly: true
+            - name: neutron-plugin-shared
+              mountPath: /opt/plugin
+            - name: neutron-bin
+              mountPath: /usr/local/lib/python2.7/site-packages/tf-plugin.pth
+              subPath: tf-plugin.pth
+              readOnly: true
+            - name: neutron-bin
+              mountPath: /var/lib/openstack/lib/python2.7/site-packages/tf-plugin.pth
+              subPath: tf-plugin.pth
+              readOnly: true
+            - name: neutron-bin
+              mountPath: /var/lib/openstack/lib/python3.6/site-packages/tf-plugin.pth
+              subPath: tf-plugin.pth
+              readOnly: true
+            {{- else }}
+            - name: neutron-etc
+              mountPath: /etc/neutron/plugins/ml2/ml2_conf.ini
+              subPath: ml2_conf.ini
+              readOnly: true
+            {{- end }}
+            {{ if ( has "sriov" .Values.network.backend ) }}
+            - name: neutron-etc
+              mountPath: /etc/neutron/plugins/ml2/sriov_agent.ini
+              subPath: sriov_agent.ini
+              readOnly: true
+            {{ end }}
+            {{- if .Values.conf.plugins.taas.taas.enabled }}
+            - name: neutron-etc
+              mountPath: /etc/neutron/taas_plugin.ini
+              subPath: taas_plugin.ini
+              readOnly: true
+            {{ end }}
+            {{- if .Values.conf.plugins.l2gateway }}
+            - name: neutron-etc
+              mountPath: /etc/neutron/l2gw_plugin.ini
+              subPath: l2gw_plugin.ini
+              readOnly: true
+            {{ end }}
+            - name: neutron-etc
+              mountPath: /etc/neutron/api-paste.ini
+              subPath: api-paste.ini
+              readOnly: true
+            - name: neutron-etc
+              mountPath: /etc/neutron/policy.yaml
+              subPath: policy.yaml
+              readOnly: true
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.endpoints.oslo_db.auth.admin.secret.tls.internal "path" "/etc/mysql/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+{{- dict "enabled" (or .Values.manifests.certificates .Values.tls.identity) "name" .Values.secrets.tls.network.server.internal "path" "/etc/neutron/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+{{- dict "enabled" $envAll.Values.manifests.certificates "name" $envAll.Values.endpoints.oslo_messaging.auth.admin.secret.tls.internal "path" "/etc/rabbitmq/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+{{ if $mounts_neutron_rpc_server.volumeMounts }}{{ toYaml $mounts_neutron_rpc_server.volumeMounts | indent 12 }}{{ end }}
+      volumes:
+        - name: pod-tmp
+          emptyDir: {}
+        - name: pod-shared
+          emptyDir: {}
+        {{- if .Values.manifests.certificates }}
+        - name: wsgi-neutron
+          emptyDir: {}
+        {{- end }}
+        - name: pod-var-neutron
+          emptyDir: {}
+        - name: neutron-bin
+          configMap:
+            name: neutron-bin
+            defaultMode: 0555
+        - name: neutron-etc
+          secret:
+            secretName: neutron-etc
+            defaultMode: 0444
+        {{- if ( has "tungstenfabric" .Values.network.backend ) }}
+        - name: neutron-plugin-shared
+          emptyDir: {}
+        {{- end }}
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.endpoints.oslo_db.auth.admin.secret.tls.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{- dict "enabled" (or .Values.manifests.certificates .Values.tls.identity) "name" .Values.secrets.tls.network.server.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{- dict "enabled" $envAll.Values.manifests.certificates "name" $envAll.Values.endpoints.oslo_messaging.auth.admin.secret.tls.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{ if $mounts_neutron_rpc_server.volumes }}{{ toYaml $mounts_neutron_rpc_server.volumes | indent 8 }}{{ end }}
+{{- end }}
diff --git a/charts/neutron/templates/deployment-server.yaml b/charts/neutron/templates/deployment-server.yaml
index 1636357..b6b634d 100644
--- a/charts/neutron/templates/deployment-server.yaml
+++ b/charts/neutron/templates/deployment-server.yaml
@@ -77,6 +77,7 @@
 {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
         configmap-bin-hash: {{ tuple "configmap-bin.yaml" . | include "helm-toolkit.utils.hash" }}
         configmap-etc-hash: {{ tuple "configmap-etc.yaml" . | include "helm-toolkit.utils.hash" }}
+{{ tuple "neutron_server" . | include "helm-toolkit.snippets.custom_pod_annotations" | indent 8 }}
 {{ dict "envAll" $envAll "podName" "neutron-server" "containerNames" (list "neutron-server" "init" "nginx") | include "helm-toolkit.snippets.kubernetes_mandatory_access_control_annotation" | indent 8 }}
     spec:
 {{ dict "envAll" $envAll "application" "neutron_server" | include "helm-toolkit.snippets.kubernetes_pod_security_context" | indent 6 }}
@@ -201,6 +202,10 @@
               mountPath: /etc/neutron/neutron.conf
               subPath: neutron.conf
               readOnly: true
+            - name: neutron-etc
+              mountPath: /etc/neutron/neutron-api-uwsgi.ini
+              subPath: neutron-api-uwsgi.ini
+              readOnly: true
             {{- if .Values.conf.neutron.DEFAULT.log_config_append }}
             - name: neutron-etc
               mountPath: {{ .Values.conf.neutron.DEFAULT.log_config_append }}
diff --git a/charts/neutron/templates/secret-db.yaml b/charts/neutron/templates/secret-db.yaml
index 47d956f..59d6d9c 100644
--- a/charts/neutron/templates/secret-db.yaml
+++ b/charts/neutron/templates/secret-db.yaml
@@ -22,6 +22,8 @@
 kind: Secret
 metadata:
   name: {{ $secretName }}
+  annotations:
+{{ tuple "oslo_db" $userClass $envAll | include "helm-toolkit.snippets.custom_secret_annotations" | indent 4 }}
 type: Opaque
 data:
 {{- if $envAll.Values.manifests.certificates }}
diff --git a/charts/neutron/templates/secret-keystone.yaml b/charts/neutron/templates/secret-keystone.yaml
index 3ce6865..c285bdd 100644
--- a/charts/neutron/templates/secret-keystone.yaml
+++ b/charts/neutron/templates/secret-keystone.yaml
@@ -21,6 +21,8 @@
 kind: Secret
 metadata:
   name: {{ $secretName }}
+  annotations:
+{{ tuple "identity" $userClass $envAll | include "helm-toolkit.snippets.custom_secret_annotations" | indent 4 }}
 type: Opaque
 data:
 {{- tuple $userClass "internal" $envAll | include "helm-toolkit.snippets.keystone_secret_openrc" | indent 2 -}}
diff --git a/charts/neutron/templates/secret_rabbitmq.yaml b/charts/neutron/templates/secret-rabbitmq.yaml
similarity index 89%
rename from charts/neutron/templates/secret_rabbitmq.yaml
rename to charts/neutron/templates/secret-rabbitmq.yaml
index 16c70e4..fd3e24f 100644
--- a/charts/neutron/templates/secret_rabbitmq.yaml
+++ b/charts/neutron/templates/secret-rabbitmq.yaml
@@ -25,6 +25,8 @@
 kind: Secret
 metadata:
   name: {{ $secretName }}
+  annotations:
+{{ tuple "oslo_messaging" $userClass $envAll | include "helm-toolkit.snippets.custom_secret_annotations" | indent 4 }}
 type: Opaque
 data:
   RABBITMQ_CONNECTION: {{ tuple "oslo_messaging" "internal" $userClass $rabbitmqProtocol $envAll | include "helm-toolkit.endpoints.authenticated_endpoint_uri_lookup" | b64enc }}
diff --git a/charts/neutron/values.yaml b/charts/neutron/values.yaml
index 8d5e944..e185837 100644
--- a/charts/neutron/values.yaml
+++ b/charts/neutron/values.yaml
@@ -32,6 +32,7 @@
     ks_endpoints: docker.io/openstackhelm/heat:stein-ubuntu_bionic
     netoffload: ghcr.io/vexxhost/netoffload:v1.0.1
     neutron_server: docker.io/openstackhelm/neutron:stein-ubuntu_bionic
+    neutron_rpc_server: docker.io/openstackhelm/neutron:stein-ubuntu_bionic
     neutron_dhcp: docker.io/openstackhelm/neutron:stein-ubuntu_bionic
     neutron_metadata: docker.io/openstackhelm/neutron:stein-ubuntu_bionic
     neutron_ovn_metadata: docker.io/openstackhelm/neutron:stein-ubuntu_bionic
@@ -93,6 +94,9 @@
   server:
     node_selector_key: openstack-control-plane
     node_selector_value: enabled
+  rpc_server:
+    node_selector_key: openstack-control-plane
+    node_selector_value: enabled
   ironic_agent:
     node_selector_key: openstack-control-plane
     node_selector_value: enabled
@@ -328,6 +332,19 @@
           service: oslo_cache
         - endpoint: internal
           service: identity
+    rpc_server:
+      jobs:
+        - neutron-db-sync
+        - neutron-rabbit-init
+      services:
+        - endpoint: internal
+          service: oslo_db
+        - endpoint: internal
+          service: oslo_messaging
+        - endpoint: internal
+          service: oslo_cache
+        - endpoint: internal
+          service: identity
     ironic_agent:
       jobs:
         - neutron-db-sync
@@ -485,6 +502,19 @@
             initialDelaySeconds: 60
             periodSeconds: 15
             timeoutSeconds: 10
+    rpc_server:
+      rpc_server:
+        readiness:
+          enabled: true
+          params:
+            periodSeconds: 15
+            timeoutSeconds: 10
+        liveness:
+          enabled: true
+          params:
+            initialDelaySeconds: 60
+            periodSeconds: 15
+            timeoutSeconds: 10
   security_context:
     neutron_dhcp_agent:
       pod:
@@ -585,6 +615,13 @@
         neutron_server:
           allowPrivilegeEscalation: false
           readOnlyRootFilesystem: true
+    neutron_rpc_server:
+      pod:
+        runAsUser: 42424
+      container:
+        neutron_rpc_server:
+          allowPrivilegeEscalation: false
+          readOnlyRootFilesystem: true
     neutron_sriov_agent:
       pod:
         runAsUser: 42424
@@ -634,6 +671,11 @@
       neutron_server:
         volumeMounts:
         volumes:
+    neutron_rpc_server:
+      init_container: null
+      neutron_rpc_server:
+        volumeMounts:
+        volumes:
     neutron_dhcp_agent:
       init_container: null
       neutron_dhcp_agent:
@@ -714,6 +756,7 @@
         volumes:
   replicas:
     server: 1
+    rpc_server: 1
     ironic_agent: 1
   lifecycle:
     upgrades:
@@ -763,6 +806,8 @@
     termination_grace_period:
       server:
         timeout: 30
+      rpc_server:
+        timeout: 30
       ironic_agent:
         timeout: 30
   resources:
@@ -1257,6 +1302,22 @@
       paste.app_factory: neutron.api.v2.router:APIRouter.factory
     filter:osprofiler:
       paste.filter_factory: osprofiler.web:WsgiMiddleware.factory
+  neutron_api_uwsgi:
+    uwsgi:
+      add-header: "Connection: close"
+      buffer-size: 65535
+      die-on-term: true
+      enable-threads: true
+      exit-on-reload: false
+      hook-master-start: unix_signal:15 gracefully_kill_them_all
+      lazy-apps: true
+      log-x-forwarded-for: true
+      master: true
+      procname-prefix-spaced: "neutron-api:"
+      route-user-agent: '^kube-probe.* donotlog:'
+      thunder-lock: true
+      worker-reload-mercy: 80
+      wsgi-file: /var/lib/openstack/bin/neutron-api
   policy: {}
   api_audit_map:
     DEFAULT:
@@ -2522,6 +2583,7 @@
   daemonset_netns_cleanup_cron: true
   deployment_ironic_agent: false
   deployment_server: true
+  deployment_rpc_server: true
   ingress_server: true
   job_bootstrap: true
   job_db_init: true
diff --git a/charts/patches/neutron/0002-add-missing-ovn-hostpath-mount.patch b/charts/patches/neutron/0002-add-missing-ovn-hostpath-mount.patch
deleted file mode 100644
index 2e5e1ba..0000000
--- a/charts/patches/neutron/0002-add-missing-ovn-hostpath-mount.patch
+++ /dev/null
@@ -1,14 +0,0 @@
-diff --git a/neutron/templates/daemonset-ovn-metadata-agent.yaml b/neutron/templates/daemonset-ovn-metadata-agent.yaml
-index f6dde55b..5c2999cf 100644
---- a/neutron/templates/daemonset-ovn-metadata-agent.yaml
-+++ b/neutron/templates/daemonset-ovn-metadata-agent.yaml
-@@ -220,6 +220,9 @@ spec:
-         - name: run
-           hostPath:
-             path: /run
-+        - name: run-openvswitch
-+          hostPath:
-+            path: /run/openvswitch
-         - name: neutron-bin
-           configMap:
-             name: neutron-bin
diff --git a/molecule/aio/group_vars/all/molecule.yml b/molecule/aio/group_vars/all/molecule.yml
index 590db4e..34cff39 100644
--- a/molecule/aio/group_vars/all/molecule.yml
+++ b/molecule/aio/group_vars/all/molecule.yml
@@ -163,6 +163,7 @@
   pod:
     replicas:
       server: 1
+      rpc_server: 1
 
 senlin_helm_values:
   conf:
diff --git a/roles/defaults/vars/main.yml b/roles/defaults/vars/main.yml
index dc90bfb..ca37422 100644
--- a/roles/defaults/vars/main.yml
+++ b/roles/defaults/vars/main.yml
@@ -129,6 +129,7 @@
   neutron_openvswitch_agent: "registry.atmosphere.dev/library/neutron:{{ atmosphere_release }}"
   neutron_ovn_metadata: "registry.atmosphere.dev/library/neutron:{{ atmosphere_release }}"
   neutron_server: "registry.atmosphere.dev/library/neutron:{{ atmosphere_release }}"
+  neutron_rpc_server: "registry.atmosphere.dev/library/neutron:{{ atmosphere_release }}"
   neutron_sriov_agent_init: "registry.atmosphere.dev/library/neutron:{{ atmosphere_release }}"
   neutron_sriov_agent: "registry.atmosphere.dev/library/neutron:{{ atmosphere_release }}"
   node_feature_discovery: registry.k8s.io/nfd/node-feature-discovery:v0.15.4
diff --git a/roles/neutron/vars/main.yml b/roles/neutron/vars/main.yml
index 151363d..5c19452 100644
--- a/roles/neutron/vars/main.yml
+++ b/roles/neutron/vars/main.yml
@@ -22,6 +22,7 @@
   pod:
     replicas:
       server: 3
+      rpc_server: 3
   conf:
     neutron:
       DEFAULT:
@@ -93,3 +94,4 @@
     daemonset_metadata_agent: false
     daemonset_ovn_metadata_agent: true
     daemonset_ovs_agent: false
+    deployment_rpc_server: false