Linux bridge to OVN
Context: production OpenStack on openstack-ansible "antelope" 27.5.1 — put there by the Zed to Antelope upgrade the autumn before — neutron ML2 with linuxbridge agents, migrated in place to OVN. About 950 networks, 370 routers, 5400 ports. Hostnames below are genericized; everything else is what I ran and what it printed. The related, older write-up — linux bridge to Open vSwitch on the same estate — is in Evergreen. The same estate's later Caracal to Dalmatian upgrade hit OVN again — a split-brain revive, with the sync rule from bug 3 confirmed once more.
Preparation
# deploy host: full /etc and /opt backup
dir=20250207
mkdir $dir
cp -r -p /etc $dir
cp /usr/local/bin/openstack-ansible.rc $dir
cp -r -p /opt $dir
# galera containers: stopped and archived on all three infra hosts
lxc-stop -n infra3_galera_container-<suffix>
lxc-stop -n infra2_galera_container-<suffix>
lxc-stop -n infra1_galera_container-<suffix>
tar czf infra1_galera_container-<suffix>_${dir}.tar.gz /var/lib/lxc/infra1_galera_container-<suffix>
# neutron venv configs on controllers and hypervisors
mkdir -p ${dir}/openstack/venvs/27
cp -r -p /openstack/venvs/*27.*/etc ${dir}/openstack/venvs/27/
# keepalived, haproxy, endpoint list
cp /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf_28062025
cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg_28062025
openstack endpoint list > openstack_endpoint_list_28062025
The switch
# remove the neutron agent container inventory
/opt/openstack-ansible/scripts/inventory-manage.py -G | awk -F '|' '/neutron_agents_cont/ {print $3}' | while read l; do /opt/openstack-ansible/scripts/inventory-manage.py --remove-item "${l}"; done
# remove neutron config overrides; comment out tunnel_bridge and
# the neutron_linuxbridge_agent group_binds in openstack_user_config.yml
vim /etc/openstack_deploy/user_variables.yml
vim /etc/openstack_deploy/openstack_user_config.yml
mkdir /etc/openstack_deploy/group_vars
vim /etc/openstack_deploy/group_vars/network_hosts # OVN variables
# deviation from the guides: northd runs in a container here, so
rm /etc/openstack_deploy/env.d/*
# stop and disable all neutron agent containers
lxc-ls -f | grep neutron_agent | awk '{print $1}' | while read l; do lxc-stop -n $l; done
sed -r -i 's|(lxc.start.auto)|#\1|g' /var/lib/lxc/*_neutron_agents_container-*/config
sed -r -i 's|(lxc.start.delay)|#\1|g' /var/lib/lxc/*_neutron_agents_container-*/config
sed -r -i 's|(lxc.group = onboot)|#\1|g' /var/lib/lxc/*_neutron_agents_container-*/config
# stop the host services
for i in neutron-linuxbridge-agent neutron-l3-agent neutron-dhcp-agent neutron-metadata-agent; do
systemctl stop $i; systemctl disable $i
done
# delete the unneeded interfaces
for i in $(ip -br link show | grep brq | awk '{print $1}'); do ip link delete $i; done
for i in $(ip -br link show | grep vxlan- | awk '{print $1}'); do ip link delete $i; done
ip -br link show | grep "br-vlan\." | awk '{print $1}' | sed 's/@.*//g' | while read l; do ip link del $l; done
# delete the agent entries from neutron (XXX = your host pattern)
for i in $(openstack network agent list | grep XXX | awk '{print $2}'); do openstack network agent delete $i; done
# playbooks (ironic computes excluded)
openstack-ansible setup-hosts.yml --limit '!ironic-compute_all'
openstack-ansible os-nova-install.yml --limit '!ironic-compute_all'
openstack-ansible os-neutron-install.yml --limit '!ironic-compute_all'
What broke, nine times — quick reference
| The error you are staring at | Fix | No. |
|---|---|---|
ValueError: :6642: bad peer name format |
add network-northd_hosts stanza to openstack_user_config.yml |
1 |
| northbound DB empty after install | neutron-ovn-db-sync-util ... repair from the neutron-server container |
2, 3 |
ovn-nbctl: database connection failed |
not dead — run sync from the cluster leader, inside the neutron-server container | 3 |
ports bound as bridge, segments still vxlan |
two SQL updates: vif_type, network_type |
4 |
leftover br-provider, eth12 |
ovs-vsctl del-br, rerun neutron-install.yml |
5 |
gateway port binding_failed, traffic fine |
heals on openvswitch-switch restart; SQL update for stuck records |
6 |
HA gateway ping stops with ovs-vswitchd |
where the gateway actually lives | 7 |
No tunnel endpoint found for HA chassis (cr-lrp port) |
HA port cleanup | 8 |
| OVN agents on the wrong hosts | stale network_hosts in config — remove, stop, disable |
9 |
NeutronDbObjectDuplicateEntry: ProviderResourceAssociation |
UPDATE ... SET provider_name = 'ovn' WHERE provider_name = 'ha' |
cleanup |
What broke, nine times
-
neutron-server would not start.
ValueError: :6642: bad peer name format. Thenetwork-northd_hostsstanza was missing fromopenstack_user_config.yml. Add it. -
Northbound DB empty after install. Sync from the neutron-server container:
neutron-ovn-db-sync-util --config-file /etc/neutron/neutron.conf \ --config-file /etc/neutron/plugins/ml2/ml2_conf.ini --ovn-neutron_sync_mode repair -
ovn-nbctl showclaimed the databases were dead. They were not. The sync only works from the cluster leader, and it has to run inside the neutron-server container — not from a controller shell. neutron-server runs the same repair code itself (launchpad 1689880). -
Old port bindings. Two updates on the cluster database:
update ml2_port_bindings set vif_type='ovs' where vif_type='bridge'; update networksegments set network_type='geneve' where network_type='vxlan'; -
Leftover bridges
br-providerandeth12.ovs-vsctl del-brboth, rerunneutron-install.yml. -
Router gateways:
binding_vif_type | binding_failed— but traffic worked. OVN implements the gateway as flows; the binding record heals itself whenopenvswitch-switchrestarts on the port's host. For a port that stays stuck, the same update as in (4) with the fullvif_detailsJSON for thatport_idfixes the record. -
A router HA gateway stopped answering ping while
ovs-vswitchdwas stopped on itsbinding_host_id. Observation, not a fix — but it tells you where the gateway actually lives. -
ovn-controller: No tunnel endpoint found for HA chassis in HA chassis group of port cr-lrp-<uuid>in the controller logs, 12 February. Related to (7); resolved with the HA port cleanup below. -
OVN agents came up on controllers that should not run them — a leftover
network_hostsdefinition inopenstack_user_config.yml. Fix: remove the stale definition, then on those hosts stop and disableovn-controller,neutron-ovn-metadata-agent,ovn-host,neutron-bgp-dragent,openvswitch-switch,ovs-vswitchd,ovsdb-server, and delete theirbr-vlanandbr-int.
Cleanup
The linuxbridge HA routers left 1092 router_ha_interface ports behind:
openstack port list --device-owner network:router_ha_interface | grep 169.254 | awk -F '|' '{print $2}' | while read l; do openstack port delete $l; done
Halfway through, neutron refused:
NeutronDbObjectDuplicateEntry: Failed to create a duplicate
ProviderResourceAssociation: for attribute(s) ['resource_id']
The records still pointed at the ha provider:
UPDATE neutron.providerresourceassociations SET provider_name = 'ovn' WHERE provider_name = 'ha';
Query OK, 582 rows affected (0.027 sec)
After that, the deletions went through.
Verify
echo "Neutron networks: $(openstack network list --format value | wc -l)" 947
echo "Neutron routers: $(openstack router list --format value | wc -l)" 373
echo "Neutron ports: $(openstack port list --format value | wc -l)" 5454
echo "Security Groups: $(openstack security group list --format value | wc -l)" 2551
echo "Security Group Rules: $(openstack security group rule list --format value | wc -l)" 6936
echo "Logical Switches: $(ovn-nbctl list Logical_Switch | grep '^_uuid' | wc -l)" 947
echo "Logical Switch Ports: $(ovn-nbctl list Logical_Switch_Port | grep '^_uuid' | wc -l)" 4975
echo "Logical Routers: $(ovn-nbctl list Logical_Router | grep '^_uuid' | wc -l)" 373
echo "Logical Router Ports: $(ovn-nbctl list Logical_Router_Port | grep '^_uuid' | wc -l)" 1836
echo "Port Groups: $(ovn-nbctl list Port_Group | grep '^_uuid' | wc -l)" 2552
Networks map to logical switches one to one, routers to logical routers. After cleanup:
ovn-nbctl list acl | wc -l 111285
ovn-sbctl lflow-list | wc -l 149752
References
This saved you a night? I do this for a living: info@wirt.ee.