In ml2 plugin delete_subnet workflow ip allocations get deleted [1] directly from database (IPAllocation model).
It conflicts with expected workflow for pluggable ipam because ipam driver in this case is not aware of ip deallocation event.
There is a call to update_port [2] but looks like it never worked correctly because by the time this code is called ip address is already removed from database by [1]. So calling update_port in this case does not trigger correct deallocate event to ipam driver.
For reference ipam driver this issue is not visible, because right after deleting ips directly from db ipam.delete_subnet is called. Deleting ipam subnet cleans up all undeleted ip allocations by FK. And this is the reason why it was not seen until now.
But issue can affect third-party ipam provides. Here is the scenario where it was found (Infoblox IPAM driver):
There is a subnet shared between OpenStack and other applications.
On attempt to delete such subnet ipam provider skips subnet deletion, since it is used by other applications,
but all ports allocated by neutron for this subnet are expected to be deallocated at this point.
Observed that dhcp port is left in allocated state on ipam provider side, because ipam driver did not receive deallocate ip address call.
Proper way to deallocate ip before subnet deletion is to use update_port for each ip deallocation instead of deleting ip allocations directly from database.
[1] https://github.com/openstack/neutron/blob/98c93a050b56bb5425d0b18456a20cf35a4ff449/neutron/plugins/ml2/plugin.py#L960
[2] https://github.com/openstack/neutron/blob/98c93a050b56bb5425d0b18456a20cf35a4ff449/neutron/plugins/ml2/plugin.py#L1020
Mark this high since this needs to be fixed to make the IPAM driver mechanism fully functional.