[pve-devel] [PATCH v2 pve-container 1/1] add ipam support

Alexandre Derumier aderumier at odiso.com
Wed May 19 08:59:49 CEST 2021


This add ipam support for nic using sdn vnets.

- if ips are specified manally, we verify that subnet exist on vnet, and we register ip in ipam
- if nic is on a vnet, but no ip is specified, we auto find the next available ips in this vnet subnet
- if a gateway is defined on the subnet, we override current vm nc gateway
- extra informations like mac address,hostname are registered in external ipam.
- if dns server exist in the zone, we register vm hostname in ipam for each ip address

- ips addresses are removed on ct destroy, nic destroy, ip change or vnet change
- snapshot rollback: if ip from snapshot is already used, we keep the current running ip
- backup restore to new vmid: if ip from backup is already used, we set ips has undef
---
 src/PVE/LXC.pm                                | 144 ++++++++++++++++++
 src/PVE/LXC/Config.pm                         |  58 +++++++
 src/PVE/LXC/Create.pm                         |  33 +++-
 src/test/Makefile                             |   5 +-
 .../ipam.db                                   |  18 +++
 .../ipam.db.expected                          |  17 +++
 .../ipam_config                               |   7 +
 .../net                                       |   7 +
 .../net.expected                              |   7 +
 .../oldnet                                    |   7 +
 .../sdn_config                                |  35 +++++
 .../ipam.db                                   |  18 +++
 .../ipam.db.expected                          |  18 +++
 .../ipam_config                               |   7 +
 .../net                                       |   7 +
 .../net.expected                              |   7 +
 .../oldnet                                    |   7 +
 .../sdn_config                                |  35 +++++
 .../ipam.db                                   |  18 +++
 .../ipam.db.expected                          |  17 +++
 .../ipam_config                               |   7 +
 .../net                                       |   7 +
 .../net.expected                              |   7 +
 .../oldnet                                    |   7 +
 .../sdn_config                                |  35 +++++
 .../ipam.db                                   |  18 +++
 .../ipam.db.expected                          |  18 +++
 .../ipam_config                               |   7 +
 .../net                                       |   6 +
 .../net.expected                              |   7 +
 .../oldnet                                    |   7 +
 .../sdn_config                                |  35 +++++
 .../ipam.db                                   |  18 +++
 .../ipam.db.expected                          |  18 +++
 .../ipam_config                               |   7 +
 .../net                                       |   6 +
 .../net.expected                              |   7 +
 .../oldnet                                    |   7 +
 .../sdn_config                                |  35 +++++
 .../ipv4_changeip_samevnet_with_ipam/ipam.db  |  18 +++
 .../ipam.db.expected                          |  18 +++
 .../ipam_config                               |   7 +
 .../ipv4_changeip_samevnet_with_ipam/net      |   7 +
 .../net.expected                              |   7 +
 .../ipv4_changeip_samevnet_with_ipam/oldnet   |   7 +
 .../sdn_config                                |  35 +++++
 .../ipv4_changeip_vmbr0_to_ipamvnet/ipam.db   |  17 +++
 .../ipam.db.expected                          |  18 +++
 .../ipam_config                               |   7 +
 .../ipams/ipv4_changeip_vmbr0_to_ipamvnet/net |   7 +
 .../net.expected                              |   7 +
 .../ipv4_changeip_vmbr0_to_ipamvnet/oldnet    |   7 +
 .../sdn_config                                |  35 +++++
 .../ipv4_changeip_vmbr0_to_noipamvnet/ipam.db |  17 +++
 .../ipam.db.expected                          |  17 +++
 .../ipam_config                               |   7 +
 .../ipv4_changeip_vmbr0_to_noipamvnet/net     |   7 +
 .../net.expected                              |   7 +
 .../ipv4_changeip_vmbr0_to_noipamvnet/oldnet  |   7 +
 .../sdn_config                                |  35 +++++
 .../ipam.db                                   |  18 +++
 .../ipam.db.expected                          |  18 +++
 .../ipam_config                               |   7 +
 .../net                                       |   7 +
 .../net.expected                              |   8 +
 .../oldnet                                    |   7 +
 .../sdn_config                                |  38 +++++
 .../ipam.db                                   |  18 +++
 .../ipam.db.expected                          |  17 +++
 .../ipam_config                               |   7 +
 .../net                                       |   8 +
 .../net.expected                              |   8 +
 .../oldnet                                    |   7 +
 .../sdn_config                                |  38 +++++
 .../ipam.db                                   |  18 +++
 .../ipam.db.expected                          |  18 +++
 .../ipam_config                               |   7 +
 .../net                                       |   7 +
 .../net.expected                              |   7 +
 .../oldnet                                    |   8 +
 .../sdn_config                                |  36 +++++
 .../ipams/ipv4_updateipam_ipamvnet/ipam.db    |  18 +++
 .../ipv4_updateipam_ipamvnet/ipam.db.expected |  18 +++
 .../ipv4_updateipam_ipamvnet/ipam_config      |   7 +
 src/test/ipams/ipv4_updateipam_ipamvnet/net   |   7 +
 .../ipv4_updateipam_ipamvnet/net.expected     |   7 +
 .../ipams/ipv4_updateipam_ipamvnet/oldnet     |   7 +
 .../ipams/ipv4_updateipam_ipamvnet/sdn_config |  35 +++++
 .../ipam.db                                   |  19 +++
 .../ipam.db.expected                          |  19 +++
 .../ipam_config                               |   7 +
 .../ipv4v6_next_free_samevnet_with_ipam/net   |   6 +
 .../net.expected                              |   8 +
 .../oldnet                                    |   8 +
 .../sdn_config                                |  39 +++++
 .../ipam.db                                   |  20 +++
 .../ipam.db.expected                          |  20 +++
 .../ipam_config                               |   7 +
 .../net                                       |   6 +
 .../net.expected                              |   8 +
 .../oldnet                                    |   8 +
 .../sdn_config                                |  39 +++++
 .../ipams/ipv4v6_updateipam_ipamvnet/ipam.db  |  19 +++
 .../ipam.db.expected                          |  19 +++
 .../ipv4v6_updateipam_ipamvnet/ipam_config    |   7 +
 src/test/ipams/ipv4v6_updateipam_ipamvnet/net |   8 +
 .../ipv4v6_updateipam_ipamvnet/net.expected   |   8 +
 .../ipams/ipv4v6_updateipam_ipamvnet/oldnet   |   8 +
 .../ipv4v6_updateipam_ipamvnet/sdn_config     |  39 +++++
 .../ipam.db                                   |  19 +++
 .../ipam.db.expected                          |  19 +++
 .../ipam_config                               |   7 +
 .../ipv4v6_updateipam_ipamvnet_failingv6/net  |   8 +
 .../net.expected                              |   8 +
 .../oldnet                                    |   8 +
 .../sdn_config                                |  35 +++++
 .../ipam.db                                   |  18 +++
 .../ipam.db.expected                          |  18 +++
 .../ipam_config                               |   7 +
 .../net                                       |   7 +
 .../net.expected                              |   7 +
 .../oldnet                                    |   7 +
 .../sdn_config                                |  35 +++++
 .../ipam.db                                   |  18 +++
 .../ipam.db.expected                          |  18 +++
 .../ipam_config                               |   7 +
 .../net                                       |   7 +
 .../net.expected                              |   8 +
 .../oldnet                                    |   7 +
 .../sdn_config                                |  37 +++++
 .../ipams/ipv6_updateipam_ipamvnet/ipam.db    |  14 ++
 .../ipv6_updateipam_ipamvnet/ipam.db.expected |  14 ++
 .../ipv6_updateipam_ipamvnet/ipam_config      |   7 +
 src/test/ipams/ipv6_updateipam_ipamvnet/net   |   7 +
 .../ipv6_updateipam_ipamvnet/net.expected     |   7 +
 .../ipams/ipv6_updateipam_ipamvnet/oldnet     |   7 +
 .../ipams/ipv6_updateipam_ipamvnet/sdn_config |  35 +++++
 src/test/run_ipam_tests.pl                    | 126 +++++++++++++++
 src/test/snapshot-input/sdn/subnets.cfg       |   0
 src/test/snapshot-test.pm                     |   1 -
 140 files changed, 2266 insertions(+), 10 deletions(-)
 create mode 100644 src/test/ipams/ipv4_changeip_ipamvnet_to_othervnet_noipam/ipam.db
 create mode 100644 src/test/ipams/ipv4_changeip_ipamvnet_to_othervnet_noipam/ipam.db.expected
 create mode 100644 src/test/ipams/ipv4_changeip_ipamvnet_to_othervnet_noipam/ipam_config
 create mode 100644 src/test/ipams/ipv4_changeip_ipamvnet_to_othervnet_noipam/net
 create mode 100644 src/test/ipams/ipv4_changeip_ipamvnet_to_othervnet_noipam/net.expected
 create mode 100644 src/test/ipams/ipv4_changeip_ipamvnet_to_othervnet_noipam/oldnet
 create mode 100644 src/test/ipams/ipv4_changeip_ipamvnet_to_othervnet_noipam/sdn_config
 create mode 100644 src/test/ipams/ipv4_changeip_ipamvnet_to_othervnetipam/ipam.db
 create mode 100644 src/test/ipams/ipv4_changeip_ipamvnet_to_othervnetipam/ipam.db.expected
 create mode 100644 src/test/ipams/ipv4_changeip_ipamvnet_to_othervnetipam/ipam_config
 create mode 100644 src/test/ipams/ipv4_changeip_ipamvnet_to_othervnetipam/net
 create mode 100644 src/test/ipams/ipv4_changeip_ipamvnet_to_othervnetipam/net.expected
 create mode 100644 src/test/ipams/ipv4_changeip_ipamvnet_to_othervnetipam/oldnet
 create mode 100644 src/test/ipams/ipv4_changeip_ipamvnet_to_othervnetipam/sdn_config
 create mode 100644 src/test/ipams/ipv4_changeip_ipamvnet_to_vmbr0_noipam/ipam.db
 create mode 100644 src/test/ipams/ipv4_changeip_ipamvnet_to_vmbr0_noipam/ipam.db.expected
 create mode 100644 src/test/ipams/ipv4_changeip_ipamvnet_to_vmbr0_noipam/ipam_config
 create mode 100644 src/test/ipams/ipv4_changeip_ipamvnet_to_vmbr0_noipam/net
 create mode 100644 src/test/ipams/ipv4_changeip_ipamvnet_to_vmbr0_noipam/net.expected
 create mode 100644 src/test/ipams/ipv4_changeip_ipamvnet_to_vmbr0_noipam/oldnet
 create mode 100644 src/test/ipams/ipv4_changeip_ipamvnet_to_vmbr0_noipam/sdn_config
 create mode 100644 src/test/ipams/ipv4_changeip_next_free_othervnet_with_ipam/ipam.db
 create mode 100644 src/test/ipams/ipv4_changeip_next_free_othervnet_with_ipam/ipam.db.expected
 create mode 100644 src/test/ipams/ipv4_changeip_next_free_othervnet_with_ipam/ipam_config
 create mode 100644 src/test/ipams/ipv4_changeip_next_free_othervnet_with_ipam/net
 create mode 100644 src/test/ipams/ipv4_changeip_next_free_othervnet_with_ipam/net.expected
 create mode 100644 src/test/ipams/ipv4_changeip_next_free_othervnet_with_ipam/oldnet
 create mode 100644 src/test/ipams/ipv4_changeip_next_free_othervnet_with_ipam/sdn_config
 create mode 100644 src/test/ipams/ipv4_changeip_next_free_samevnet_with_ipam/ipam.db
 create mode 100644 src/test/ipams/ipv4_changeip_next_free_samevnet_with_ipam/ipam.db.expected
 create mode 100644 src/test/ipams/ipv4_changeip_next_free_samevnet_with_ipam/ipam_config
 create mode 100644 src/test/ipams/ipv4_changeip_next_free_samevnet_with_ipam/net
 create mode 100644 src/test/ipams/ipv4_changeip_next_free_samevnet_with_ipam/net.expected
 create mode 100644 src/test/ipams/ipv4_changeip_next_free_samevnet_with_ipam/oldnet
 create mode 100644 src/test/ipams/ipv4_changeip_next_free_samevnet_with_ipam/sdn_config
 create mode 100644 src/test/ipams/ipv4_changeip_samevnet_with_ipam/ipam.db
 create mode 100644 src/test/ipams/ipv4_changeip_samevnet_with_ipam/ipam.db.expected
 create mode 100644 src/test/ipams/ipv4_changeip_samevnet_with_ipam/ipam_config
 create mode 100644 src/test/ipams/ipv4_changeip_samevnet_with_ipam/net
 create mode 100644 src/test/ipams/ipv4_changeip_samevnet_with_ipam/net.expected
 create mode 100644 src/test/ipams/ipv4_changeip_samevnet_with_ipam/oldnet
 create mode 100644 src/test/ipams/ipv4_changeip_samevnet_with_ipam/sdn_config
 create mode 100644 src/test/ipams/ipv4_changeip_vmbr0_to_ipamvnet/ipam.db
 create mode 100644 src/test/ipams/ipv4_changeip_vmbr0_to_ipamvnet/ipam.db.expected
 create mode 100644 src/test/ipams/ipv4_changeip_vmbr0_to_ipamvnet/ipam_config
 create mode 100644 src/test/ipams/ipv4_changeip_vmbr0_to_ipamvnet/net
 create mode 100644 src/test/ipams/ipv4_changeip_vmbr0_to_ipamvnet/net.expected
 create mode 100644 src/test/ipams/ipv4_changeip_vmbr0_to_ipamvnet/oldnet
 create mode 100644 src/test/ipams/ipv4_changeip_vmbr0_to_ipamvnet/sdn_config
 create mode 100644 src/test/ipams/ipv4_changeip_vmbr0_to_noipamvnet/ipam.db
 create mode 100644 src/test/ipams/ipv4_changeip_vmbr0_to_noipamvnet/ipam.db.expected
 create mode 100644 src/test/ipams/ipv4_changeip_vmbr0_to_noipamvnet/ipam_config
 create mode 100644 src/test/ipams/ipv4_changeip_vmbr0_to_noipamvnet/net
 create mode 100644 src/test/ipams/ipv4_changeip_vmbr0_to_noipamvnet/net.expected
 create mode 100644 src/test/ipams/ipv4_changeip_vmbr0_to_noipamvnet/oldnet
 create mode 100644 src/test/ipams/ipv4_changeip_vmbr0_to_noipamvnet/sdn_config
 create mode 100644 src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetipam/ipam.db
 create mode 100644 src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetipam/ipam.db.expected
 create mode 100644 src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetipam/ipam_config
 create mode 100644 src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetipam/net
 create mode 100644 src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetipam/net.expected
 create mode 100644 src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetipam/oldnet
 create mode 100644 src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetipam/sdn_config
 create mode 100644 src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetnoipam/ipam.db
 create mode 100644 src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetnoipam/ipam.db.expected
 create mode 100644 src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetnoipam/ipam_config
 create mode 100644 src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetnoipam/net
 create mode 100644 src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetnoipam/net.expected
 create mode 100644 src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetnoipam/oldnet
 create mode 100644 src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetnoipam/sdn_config
 create mode 100644 src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_nogateway_othervnetipam/ipam.db
 create mode 100644 src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_nogateway_othervnetipam/ipam.db.expected
 create mode 100644 src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_nogateway_othervnetipam/ipam_config
 create mode 100644 src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_nogateway_othervnetipam/net
 create mode 100644 src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_nogateway_othervnetipam/net.expected
 create mode 100644 src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_nogateway_othervnetipam/oldnet
 create mode 100644 src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_nogateway_othervnetipam/sdn_config
 create mode 100644 src/test/ipams/ipv4_updateipam_ipamvnet/ipam.db
 create mode 100644 src/test/ipams/ipv4_updateipam_ipamvnet/ipam.db.expected
 create mode 100644 src/test/ipams/ipv4_updateipam_ipamvnet/ipam_config
 create mode 100644 src/test/ipams/ipv4_updateipam_ipamvnet/net
 create mode 100644 src/test/ipams/ipv4_updateipam_ipamvnet/net.expected
 create mode 100644 src/test/ipams/ipv4_updateipam_ipamvnet/oldnet
 create mode 100644 src/test/ipams/ipv4_updateipam_ipamvnet/sdn_config
 create mode 100644 src/test/ipams/ipv4v6_next_free_samevnet_with_ipam/ipam.db
 create mode 100644 src/test/ipams/ipv4v6_next_free_samevnet_with_ipam/ipam.db.expected
 create mode 100644 src/test/ipams/ipv4v6_next_free_samevnet_with_ipam/ipam_config
 create mode 100644 src/test/ipams/ipv4v6_next_free_samevnet_with_ipam/net
 create mode 100644 src/test/ipams/ipv4v6_next_free_samevnet_with_ipam/net.expected
 create mode 100644 src/test/ipams/ipv4v6_next_free_samevnet_with_ipam/oldnet
 create mode 100644 src/test/ipams/ipv4v6_next_free_samevnet_with_ipam/sdn_config
 create mode 100644 src/test/ipams/ipv4v6_next_free_samevnet_with_ipam_failingv6/ipam.db
 create mode 100644 src/test/ipams/ipv4v6_next_free_samevnet_with_ipam_failingv6/ipam.db.expected
 create mode 100644 src/test/ipams/ipv4v6_next_free_samevnet_with_ipam_failingv6/ipam_config
 create mode 100644 src/test/ipams/ipv4v6_next_free_samevnet_with_ipam_failingv6/net
 create mode 100644 src/test/ipams/ipv4v6_next_free_samevnet_with_ipam_failingv6/net.expected
 create mode 100644 src/test/ipams/ipv4v6_next_free_samevnet_with_ipam_failingv6/oldnet
 create mode 100644 src/test/ipams/ipv4v6_next_free_samevnet_with_ipam_failingv6/sdn_config
 create mode 100644 src/test/ipams/ipv4v6_updateipam_ipamvnet/ipam.db
 create mode 100644 src/test/ipams/ipv4v6_updateipam_ipamvnet/ipam.db.expected
 create mode 100644 src/test/ipams/ipv4v6_updateipam_ipamvnet/ipam_config
 create mode 100644 src/test/ipams/ipv4v6_updateipam_ipamvnet/net
 create mode 100644 src/test/ipams/ipv4v6_updateipam_ipamvnet/net.expected
 create mode 100644 src/test/ipams/ipv4v6_updateipam_ipamvnet/oldnet
 create mode 100644 src/test/ipams/ipv4v6_updateipam_ipamvnet/sdn_config
 create mode 100644 src/test/ipams/ipv4v6_updateipam_ipamvnet_failingv6/ipam.db
 create mode 100644 src/test/ipams/ipv4v6_updateipam_ipamvnet_failingv6/ipam.db.expected
 create mode 100644 src/test/ipams/ipv4v6_updateipam_ipamvnet_failingv6/ipam_config
 create mode 100644 src/test/ipams/ipv4v6_updateipam_ipamvnet_failingv6/net
 create mode 100644 src/test/ipams/ipv4v6_updateipam_ipamvnet_failingv6/net.expected
 create mode 100644 src/test/ipams/ipv4v6_updateipam_ipamvnet_failingv6/oldnet
 create mode 100644 src/test/ipams/ipv4v6_updateipam_ipamvnet_failingv6/sdn_config
 create mode 100644 src/test/ipams/ipv6_changeip_ipamvnet_to_othervnetipam/ipam.db
 create mode 100644 src/test/ipams/ipv6_changeip_ipamvnet_to_othervnetipam/ipam.db.expected
 create mode 100644 src/test/ipams/ipv6_changeip_ipamvnet_to_othervnetipam/ipam_config
 create mode 100644 src/test/ipams/ipv6_changeip_ipamvnet_to_othervnetipam/net
 create mode 100644 src/test/ipams/ipv6_changeip_ipamvnet_to_othervnetipam/net.expected
 create mode 100644 src/test/ipams/ipv6_changeip_ipamvnet_to_othervnetipam/oldnet
 create mode 100644 src/test/ipams/ipv6_changeip_ipamvnet_to_othervnetipam/sdn_config
 create mode 100644 src/test/ipams/ipv6_gateway_changeip_ipamvnet_to_gateway_othervnetipam/ipam.db
 create mode 100644 src/test/ipams/ipv6_gateway_changeip_ipamvnet_to_gateway_othervnetipam/ipam.db.expected
 create mode 100644 src/test/ipams/ipv6_gateway_changeip_ipamvnet_to_gateway_othervnetipam/ipam_config
 create mode 100644 src/test/ipams/ipv6_gateway_changeip_ipamvnet_to_gateway_othervnetipam/net
 create mode 100644 src/test/ipams/ipv6_gateway_changeip_ipamvnet_to_gateway_othervnetipam/net.expected
 create mode 100644 src/test/ipams/ipv6_gateway_changeip_ipamvnet_to_gateway_othervnetipam/oldnet
 create mode 100644 src/test/ipams/ipv6_gateway_changeip_ipamvnet_to_gateway_othervnetipam/sdn_config
 create mode 100644 src/test/ipams/ipv6_updateipam_ipamvnet/ipam.db
 create mode 100644 src/test/ipams/ipv6_updateipam_ipamvnet/ipam.db.expected
 create mode 100644 src/test/ipams/ipv6_updateipam_ipamvnet/ipam_config
 create mode 100644 src/test/ipams/ipv6_updateipam_ipamvnet/net
 create mode 100644 src/test/ipams/ipv6_updateipam_ipamvnet/net.expected
 create mode 100644 src/test/ipams/ipv6_updateipam_ipamvnet/oldnet
 create mode 100644 src/test/ipams/ipv6_updateipam_ipamvnet/sdn_config
 create mode 100755 src/test/run_ipam_tests.pl
 create mode 100644 src/test/snapshot-input/sdn/subnets.cfg

diff --git a/src/PVE/LXC.pm b/src/PVE/LXC.pm
index 7e6f378..a1eee0e 100644
--- a/src/PVE/LXC.pm
+++ b/src/PVE/LXC.pm
@@ -847,6 +847,9 @@ sub destroy_lxc_container {
     rmdir "/var/lib/lxc/$vmid/rootfs";
     unlink "/var/lib/lxc/$vmid/config";
     rmdir "/var/lib/lxc/$vmid";
+
+    PVE::LXC::destroy_net_ip($conf);
+
     if (defined $replacement_conf) {
 	PVE::LXC::Config->write_config($vmid, $replacement_conf);
     } else {
@@ -1077,6 +1080,147 @@ sub update_ipconfig {
 
 }
 
+sub is_static_ip {
+    my ($ip) = @_;
+
+    return 1 if $ip !~ m/(dhcp|manual|auto)$/;
+}
+
+sub ip_has_changed {
+    my ($oldip, $ip) = @_;
+
+    return 1 if !$oldip && $ip;
+    return 1 if !$ip && $oldip;
+    return 1 if $ip && $oldip && $ip ne $oldip;
+}
+
+my $add_net_ip = sub {
+    my ($version, $net, $oldnet, $hostname, $oldhostname, $description) = @_;
+
+    my $oldbridge = $oldnet->{bridge};
+    my $bridge = $net->{bridge};
+    my $mac = $net->{hwaddr};
+    my $ipfield = $version == 4 ? "ip" : "ip6";
+    my $ip = $net->{$ipfield};
+    my $oldip = $oldnet->{$ipfield};
+    my $subnets = PVE::Network::SDN::Vnets::get_subnets($bridge);
+    return if !keys %{$subnets};
+
+    eval {
+	if (!$ip) {
+	    my $next_free_ip = PVE::Network::SDN::Vnets::get_next_free_cidr($bridge, $hostname, $mac, $description, $version);
+	    $net->{$ipfield} = $next_free_ip if $next_free_ip;
+	} elsif (is_static_ip($ip)) {
+	    if (!ip_has_changed($oldip, $ip)) {
+		#update ip attributes if no ip address change
+		PVE::Network::SDN::Vnets::update_cidr($bridge, $ip, $hostname, $oldhostname, $mac, $description);
+	    } else {
+		PVE::Network::SDN::Vnets::add_cidr($bridge, $ip, $hostname, $mac, $description);
+	    }
+	}
+    };
+    if ($@) {
+	die $@;
+    }
+};
+
+my $del_net_ip = sub {
+    my ($version, $oldnet, $net, $hostname, $description) = @_;
+
+    my $oldbridge = $oldnet->{bridge};
+    my $bridge = $net->{bridge};
+    my $ip = $version == 4 ? $net->{ip} : $net->{ip6};
+    my $oldip = $version == 4 ? $oldnet->{ip} : $oldnet->{ip6};
+
+    return if !$oldip || !is_static_ip($oldip);
+
+    my $subnets = PVE::Network::SDN::Vnets::get_subnets($oldbridge);
+    return if !keys %{$subnets};
+
+    eval {
+	PVE::Network::SDN::Vnets::del_cidr($oldbridge, $oldip, $hostname, $description) if !$bridge || $bridge ne $oldbridge || !$ip || $ip ne $oldip;
+    };
+    warn $@ if $@;
+};
+
+
+my $update_net_gateway = sub {
+    my ($version, $net) = @_;
+
+    my $bridge = $net->{bridge};
+    my $netip = $version == 4 ? $net->{ip} : $net->{ip6};
+    my $gwfield = $version == 4 ? "gw" : "gw6";
+
+    return if (!$netip || !is_static_ip($netip));
+
+    my $subnets = PVE::Network::SDN::Vnets::get_subnets($bridge);
+    return if !keys %{$subnets};
+
+    #update gateway
+    my ($ip, $mask) = split(/\//, $netip);
+    my ($subnetid, $subnet) = PVE::Network::SDN::Subnets::find_ip_subnet($ip, $mask, $subnets);
+    my $gw = $subnet->{gateway} if $subnet->{gateway};
+    $net->{$gwfield} = $gw if $gw;
+
+};
+
+sub destroy_net_ip {
+    my ($conf) = @_;
+
+    return if !$have_sdn;
+
+    foreach my $opt (keys %$conf) {
+	next if $opt !~ m/^net(\d+)$/;
+	my $netid = $1;
+	my $oldnet = PVE::LXC::Config->parse_lxc_network($conf->{$opt});
+	my $hostname = $conf->{hostname};
+	my $description = '';
+	delete_net_ip($hostname, $oldnet, undef, $description);
+    }
+}
+
+sub update_net_ip {
+    my ($net, $oldnet, $hostname, $oldhostname, $description) = @_;
+
+    return if !$have_sdn;
+
+    eval {
+	&$add_net_ip(4, $net, $oldnet, $hostname, $oldhostname, $description);
+    };
+    if ($@) {
+	$net->{ip} = $oldnet->{ip};
+	die "can't change ip4: $@\n";
+    }
+
+    eval {
+	&$add_net_ip(6, $net, $oldnet, $hostname, $oldhostname, $description);
+    };
+    if ($@) {
+	my $err = $@;
+	#if error, delete previously added ipv4
+	eval {
+	    PVE::Network::SDN::Vnets::del_cidr($net->{bridge}, $net->{ip}, $hostname, $description) if ip_has_changed($oldnet->{ip}, $net->{ip});
+	};
+	$net->{ip6} = $oldnet->{ip6};
+	$net->{ip} = $oldnet->{ip};
+	die "error change ipv6: $err\n";
+    }
+
+    delete_net_ip($oldhostname, $oldnet, $net, $description);
+
+    &$update_net_gateway(4, $net);
+    &$update_net_gateway(6, $net);
+}
+
+sub delete_net_ip {
+    my ($hostname, $oldnet, $net, $description) = @_;
+
+    return if !$have_sdn;
+
+    &$del_net_ip(4, $oldnet, $net, $hostname, $description);
+    &$del_net_ip(6, $oldnet, $net, $hostname, $description);
+}
+
 my $open_namespace = sub {
     my ($vmid, $pid, $kind) = @_;
     sysopen my $fd, "/proc/$pid/ns/$kind", O_RDONLY
diff --git a/src/PVE/LXC/Config.pm b/src/PVE/LXC/Config.pm
index 7b82f65..b0cf298 100644
--- a/src/PVE/LXC/Config.pm
+++ b/src/PVE/LXC/Config.pm
@@ -213,6 +213,43 @@ sub __snapshot_delete_vol_snapshot {
     push @$unused, $mountpoint->{volume};
 }
 
+sub __snapshot_rollback_hook {
+    my ($class, $vmid, $conf, $snap, $prepare, $data) = @_;
+
+    if($prepare) {
+	$data->{oldconf} = $conf;
+    } else {
+	my $noerr = 1;  #if ip change and already use, we keep the current ip
+	my $oldconf = $data->{oldconf};
+	#update ip of current and new net interface
+	foreach my $opt (keys %$conf) {
+	    next if $opt !~ m/^net(\d+)$/;
+	    my $netid = $1;
+	    my $oldnet = $class->parse_lxc_network($oldconf->{$opt});
+	    my $net = $class->parse_lxc_network($conf->{$opt});
+	    my $hostname = $conf->{hostname};
+	    my $description = "vm:$vmid net:$netid";
+	    eval {
+		PVE::LXC::update_net_ip($net, $oldnet, $hostname, $hostname, $description);
+	    };
+	    if ($@) {
+		warn "error: $@ : keep current ip configuration\n";
+		$conf->{$opt} = $class->print_lxc_network($net);
+	    }
+	}
+
+	#remove ip of removed net interface
+	foreach my $opt (keys %$oldconf) {
+	    next if $opt !~ m/^net(\d+)$/;
+	    next if defined($conf->{$opt});
+	    my $netid = $1;
+	    my $oldnet = $class->parse_lxc_network($oldconf->{$opt});
+	    my $hostname = $oldconf->{hostname};
+	    my $description = "vm:$vmid net:$netid";
+	    delete_net_ip($hostname, $oldnet, undef, "vm:$vmid net:$netid");
+	}
+    }
+}
 sub __snapshot_rollback_vol_possible {
     my ($class, $mountpoint, $snapname) = @_;
 
@@ -1044,6 +1081,10 @@ sub update_pct_config {
 	    $class->check_protection($conf, "can't remove CT $vmid drive '$opt'");
 	} elsif ($opt eq 'unprivileged') {
 	    die "unable to delete read-only option: '$opt'\n";
+	} elsif ($opt =~ m/^net(\d+)$/) {
+	    my $netid = $1;
+	    my $oldnet = $class->parse_lxc_network($conf->{$opt});
+	    delete_net_ip($conf->{hostname}, $oldnet, undef, "vm:$vmid net:$netid");
 	}
 	$class->add_to_pending_delete($conf, $opt);
     }
@@ -1071,7 +1112,23 @@ sub update_pct_config {
 	    $value = PVE::LXC::verify_searchdomain_list($value);
 	} elsif ($opt eq 'unprivileged') {
 	    die "unable to modify read-only option: '$opt'\n";
+	} elsif ($opt =~ m/^net(\d+)$/) {
+		my $netid = $1;
+		my $net = $class->parse_lxc_network($value);
+		my $oldnet = $class->parse_lxc_network($conf->{$opt});
+		my $hostname = $param->{hostname} ? $param->{hostname} : $conf->{hostname};
+		PVE::LXC::update_net_ip($net, $oldnet, $hostname, $hostname, "vm:$vmid net:$netid");
+		$value = $class->print_lxc_network($net);
+	} elsif ($opt eq 'hostname') {
+	    #if hostname change, update ipam + dns for each ip
+	    foreach my $netopt (sort keys %$conf) {
+	        next if $netopt !~ m/^net(\d+)$/;
+		my $netid = $1;
+		my $net = $class->parse_lxc_network($conf->{$netopt});
+		PVE::LXC::update_net_ip($net, $net, $value, $conf->{hostname}, "vm:$vmid net:$netid");
+	    }
 	}
+
 	$conf->{pending}->{$opt} = $value;
 	$class->remove_from_pending_delete($conf, $opt);
     }
@@ -1663,4 +1720,5 @@ sub get_backup_volumes {
     return $return_volumes;
 }
 
+
 1;
diff --git a/src/PVE/LXC/Create.pm b/src/PVE/LXC/Create.pm
index 82d7ad9..e43433b 100644
--- a/src/PVE/LXC/Create.pm
+++ b/src/PVE/LXC/Create.pm
@@ -278,7 +278,7 @@ sub restore_configuration_from_proxmox_backup {
 
     my $oldconf = recover_config_from_proxmox_backup($storage_cfg, $archive, $vmid);
 
-    sanitize_and_merge_config($conf, $oldconf, $restricted, $unique);
+    sanitize_and_merge_config($conf, $oldconf, $restricted, $unique, $vmid);
 
     my $cmd = "files";
 
@@ -304,7 +304,7 @@ sub restore_configuration_from_proxmox_backup {
 }
 
 sub sanitize_and_merge_config {
-    my ($conf, $oldconf, $restricted, $unique) = @_;
+    my ($conf, $oldconf, $restricted, $unique, $vmid) = @_;
 
     foreach my $key (keys %$oldconf) {
 	next if $key eq 'digest' || $key eq 'rootfs' || $key eq 'snapshots' || $key eq 'unprivileged' || $key eq 'parent';
@@ -325,12 +325,29 @@ sub sanitize_and_merge_config {
 	    next;
 	}
 
-	if ($unique && $key =~ /^net\d+$/) {
+	if ($key =~ m/^net(\d+)$/) {
+	    my $netid = $1;
 	    my $net = PVE::LXC::Config->parse_lxc_network($oldconf->{$key});
-	    my $dc = PVE::Cluster::cfs_read_file('datacenter.cfg');
-	    $net->{hwaddr} = PVE::Tools::random_ether_addr($dc->{mac_prefix});
-	    $conf->{$key} = PVE::LXC::Config->print_lxc_network($net);
-	    next;
+	    my $hostname = $oldconf->{hostname};
+	    my $description = "vm:$vmid net:$netid";
+
+	    if ($unique) {
+		my $dc = PVE::Cluster::cfs_read_file('datacenter.cfg');
+		$net->{hwaddr} = PVE::Tools::random_ether_addr($dc->{mac_prefix});
+		$conf->{$key} = PVE::LXC::Config->print_lxc_network($net);
+	    }
+
+	    eval {
+		PVE::LXC::update_net_ip($net, undef, $hostname, $hostname, $description);
+	    };
+	    if ($@) {
+		warn "error: $@ : remove ipconfig from net$netid\n";
+		$net->{ip} = undef;
+		$net->{gw} = undef;
+		$net->{ip6} = undef;
+		$net->{gw6} = undef;
+		$conf->{$key} = PVE::LXC::Config->print_lxc_network($net);
+	    }
 	}
 	$conf->{$key} = $oldconf->{$key} if !defined($conf->{$key});
     }
@@ -348,7 +365,7 @@ sub restore_configuration_from_etc_vzdump {
 	my $raw = PVE::Tools::file_get_contents($pct_cfg_fn);
 	my $oldconf = PVE::LXC::Config::parse_pct_config("/lxc/$vmid.conf", $raw);
 
-	sanitize_and_merge_config($conf, $oldconf, $restricted, $unique);
+	sanitize_and_merge_config($conf, $oldconf, $restricted, $unique, $vmid);
 
 	unlink($pct_cfg_fn);
 
diff --git a/src/test/Makefile b/src/test/Makefile
index 8734879..68133aa 100644
--- a/src/test/Makefile
+++ b/src/test/Makefile
@@ -2,7 +2,7 @@ RUN_USERNS := lxc-usernsexec -m "u:0:`id -u`:1" -m "g:0:`id -g`:1" --
 
 all: test
 
-test: test_setup test_snapshot test_bindmount
+test: test_setup test_snapshot test_bindmount test_ipam
 
 test_setup: run_setup_tests.pl
 	$(RUN_USERNS) ./run_setup_tests.pl
@@ -13,5 +13,8 @@ test_snapshot: run_snapshot_tests.pl
 test_bindmount: bindmount_test.pl
 	$(RUN_USERNS) ./bindmount_test.pl
 
+test_ipam: run_ipam_tests.pl
+	./run_ipam_tests.pl
+
 clean:
 	rm -rf tmprootfs
diff --git a/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnet_noipam/ipam.db b/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnet_noipam/ipam.db
new file mode 100644
index 0000000..d03cc04
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnet_noipam/ipam.db
@@ -0,0 +1,18 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+			"192.168.0.1" => {}
+		    }
+		},
+		"192.168.1.0/30" => {
+		    "ips" =>{
+		    }
+		},
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnet_noipam/ipam.db.expected b/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnet_noipam/ipam.db.expected
new file mode 100644
index 0000000..3d36a24
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnet_noipam/ipam.db.expected
@@ -0,0 +1,17 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+		    }
+		},
+		"192.168.1.0/30" => {
+		    "ips" =>{
+		    }
+		},
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnet_noipam/ipam_config b/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnet_noipam/ipam_config
new file mode 100644
index 0000000..f5f36ad
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnet_noipam/ipam_config
@@ -0,0 +1,7 @@
+{
+          'ids' => {
+                     'pve' => {
+                                'type' => 'pve'
+                              },
+                   },
+}
diff --git a/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnet_noipam/net b/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnet_noipam/net
new file mode 100644
index 0000000..26740b4
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnet_noipam/net
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet3',
+    'ip' => '192.168.2.1/30',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnet_noipam/net.expected b/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnet_noipam/net.expected
new file mode 100644
index 0000000..26740b4
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnet_noipam/net.expected
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet3',
+    'ip' => '192.168.2.1/30',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnet_noipam/oldnet b/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnet_noipam/oldnet
new file mode 100644
index 0000000..fe003a3
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnet_noipam/oldnet
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'ip' => '192.168.0.1/30',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnet_noipam/sdn_config b/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnet_noipam/sdn_config
new file mode 100644
index 0000000..43e142f
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnet_noipam/sdn_config
@@ -0,0 +1,35 @@
+{
+  version => 1,
+  vnets   => {
+               ids => {
+                        myvnet => { type => "vnet", zone => "myzone" },
+                        myvnet2 => { type => "vnet", zone => "myzone" },
+                        myvnet3 => { type => "vnet", zone => "myzone2" },
+                      },
+             },
+
+  zones   => {
+               ids => { 
+			myzone => { ipam => "pve", type =>"simple" },
+			myzone2 => { type =>"simple" },
+		      },
+             },
+
+  subnets => {
+              ids => { 
+			'myzone-192.168.0.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet',
+                                                  },
+			'myzone-192.168.1.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet2',
+                                                  },
+			'myzone2-192.168.2.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet3',
+                                                  },
+                     }
+
+             }
+}
diff --git a/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnetipam/ipam.db b/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnetipam/ipam.db
new file mode 100644
index 0000000..d03cc04
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnetipam/ipam.db
@@ -0,0 +1,18 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+			"192.168.0.1" => {}
+		    }
+		},
+		"192.168.1.0/30" => {
+		    "ips" =>{
+		    }
+		},
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnetipam/ipam.db.expected b/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnetipam/ipam.db.expected
new file mode 100644
index 0000000..f576915
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnetipam/ipam.db.expected
@@ -0,0 +1,18 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+		    }
+		},
+		"192.168.1.0/30" => {
+		    "ips" =>{
+			"192.168.1.1" => {}
+		    }
+		},
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnetipam/ipam_config b/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnetipam/ipam_config
new file mode 100644
index 0000000..f5f36ad
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnetipam/ipam_config
@@ -0,0 +1,7 @@
+{
+          'ids' => {
+                     'pve' => {
+                                'type' => 'pve'
+                              },
+                   },
+}
diff --git a/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnetipam/net b/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnetipam/net
new file mode 100644
index 0000000..4031d65
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnetipam/net
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet2',
+    'ip' => '192.168.1.1/30',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnetipam/net.expected b/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnetipam/net.expected
new file mode 100644
index 0000000..4031d65
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnetipam/net.expected
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet2',
+    'ip' => '192.168.1.1/30',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnetipam/oldnet b/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnetipam/oldnet
new file mode 100644
index 0000000..fe003a3
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnetipam/oldnet
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'ip' => '192.168.0.1/30',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnetipam/sdn_config b/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnetipam/sdn_config
new file mode 100644
index 0000000..43e142f
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_ipamvnet_to_othervnetipam/sdn_config
@@ -0,0 +1,35 @@
+{
+  version => 1,
+  vnets   => {
+               ids => {
+                        myvnet => { type => "vnet", zone => "myzone" },
+                        myvnet2 => { type => "vnet", zone => "myzone" },
+                        myvnet3 => { type => "vnet", zone => "myzone2" },
+                      },
+             },
+
+  zones   => {
+               ids => { 
+			myzone => { ipam => "pve", type =>"simple" },
+			myzone2 => { type =>"simple" },
+		      },
+             },
+
+  subnets => {
+              ids => { 
+			'myzone-192.168.0.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet',
+                                                  },
+			'myzone-192.168.1.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet2',
+                                                  },
+			'myzone2-192.168.2.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet3',
+                                                  },
+                     }
+
+             }
+}
diff --git a/src/test/ipams/ipv4_changeip_ipamvnet_to_vmbr0_noipam/ipam.db b/src/test/ipams/ipv4_changeip_ipamvnet_to_vmbr0_noipam/ipam.db
new file mode 100644
index 0000000..d03cc04
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_ipamvnet_to_vmbr0_noipam/ipam.db
@@ -0,0 +1,18 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+			"192.168.0.1" => {}
+		    }
+		},
+		"192.168.1.0/30" => {
+		    "ips" =>{
+		    }
+		},
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv4_changeip_ipamvnet_to_vmbr0_noipam/ipam.db.expected b/src/test/ipams/ipv4_changeip_ipamvnet_to_vmbr0_noipam/ipam.db.expected
new file mode 100644
index 0000000..3d36a24
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_ipamvnet_to_vmbr0_noipam/ipam.db.expected
@@ -0,0 +1,17 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+		    }
+		},
+		"192.168.1.0/30" => {
+		    "ips" =>{
+		    }
+		},
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv4_changeip_ipamvnet_to_vmbr0_noipam/ipam_config b/src/test/ipams/ipv4_changeip_ipamvnet_to_vmbr0_noipam/ipam_config
new file mode 100644
index 0000000..f5f36ad
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_ipamvnet_to_vmbr0_noipam/ipam_config
@@ -0,0 +1,7 @@
+{
+          'ids' => {
+                     'pve' => {
+                                'type' => 'pve'
+                              },
+                   },
+}
diff --git a/src/test/ipams/ipv4_changeip_ipamvnet_to_vmbr0_noipam/net b/src/test/ipams/ipv4_changeip_ipamvnet_to_vmbr0_noipam/net
new file mode 100644
index 0000000..908f573
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_ipamvnet_to_vmbr0_noipam/net
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'vmbr0',
+    'ip' => '192.168.0.1/30',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_changeip_ipamvnet_to_vmbr0_noipam/net.expected b/src/test/ipams/ipv4_changeip_ipamvnet_to_vmbr0_noipam/net.expected
new file mode 100644
index 0000000..908f573
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_ipamvnet_to_vmbr0_noipam/net.expected
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'vmbr0',
+    'ip' => '192.168.0.1/30',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_changeip_ipamvnet_to_vmbr0_noipam/oldnet b/src/test/ipams/ipv4_changeip_ipamvnet_to_vmbr0_noipam/oldnet
new file mode 100644
index 0000000..fe003a3
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_ipamvnet_to_vmbr0_noipam/oldnet
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'ip' => '192.168.0.1/30',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_changeip_ipamvnet_to_vmbr0_noipam/sdn_config b/src/test/ipams/ipv4_changeip_ipamvnet_to_vmbr0_noipam/sdn_config
new file mode 100644
index 0000000..43e142f
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_ipamvnet_to_vmbr0_noipam/sdn_config
@@ -0,0 +1,35 @@
+{
+  version => 1,
+  vnets   => {
+               ids => {
+                        myvnet => { type => "vnet", zone => "myzone" },
+                        myvnet2 => { type => "vnet", zone => "myzone" },
+                        myvnet3 => { type => "vnet", zone => "myzone2" },
+                      },
+             },
+
+  zones   => {
+               ids => { 
+			myzone => { ipam => "pve", type =>"simple" },
+			myzone2 => { type =>"simple" },
+		      },
+             },
+
+  subnets => {
+              ids => { 
+			'myzone-192.168.0.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet',
+                                                  },
+			'myzone-192.168.1.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet2',
+                                                  },
+			'myzone2-192.168.2.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet3',
+                                                  },
+                     }
+
+             }
+}
diff --git a/src/test/ipams/ipv4_changeip_next_free_othervnet_with_ipam/ipam.db b/src/test/ipams/ipv4_changeip_next_free_othervnet_with_ipam/ipam.db
new file mode 100644
index 0000000..d03cc04
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_next_free_othervnet_with_ipam/ipam.db
@@ -0,0 +1,18 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+			"192.168.0.1" => {}
+		    }
+		},
+		"192.168.1.0/30" => {
+		    "ips" =>{
+		    }
+		},
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv4_changeip_next_free_othervnet_with_ipam/ipam.db.expected b/src/test/ipams/ipv4_changeip_next_free_othervnet_with_ipam/ipam.db.expected
new file mode 100644
index 0000000..f576915
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_next_free_othervnet_with_ipam/ipam.db.expected
@@ -0,0 +1,18 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+		    }
+		},
+		"192.168.1.0/30" => {
+		    "ips" =>{
+			"192.168.1.1" => {}
+		    }
+		},
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv4_changeip_next_free_othervnet_with_ipam/ipam_config b/src/test/ipams/ipv4_changeip_next_free_othervnet_with_ipam/ipam_config
new file mode 100644
index 0000000..f5f36ad
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_next_free_othervnet_with_ipam/ipam_config
@@ -0,0 +1,7 @@
+{
+          'ids' => {
+                     'pve' => {
+                                'type' => 'pve'
+                              },
+                   },
+}
diff --git a/src/test/ipams/ipv4_changeip_next_free_othervnet_with_ipam/net b/src/test/ipams/ipv4_changeip_next_free_othervnet_with_ipam/net
new file mode 100644
index 0000000..a73e889
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_next_free_othervnet_with_ipam/net
@@ -0,0 +1,6 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet2',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_changeip_next_free_othervnet_with_ipam/net.expected b/src/test/ipams/ipv4_changeip_next_free_othervnet_with_ipam/net.expected
new file mode 100644
index 0000000..4031d65
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_next_free_othervnet_with_ipam/net.expected
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet2',
+    'ip' => '192.168.1.1/30',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_changeip_next_free_othervnet_with_ipam/oldnet b/src/test/ipams/ipv4_changeip_next_free_othervnet_with_ipam/oldnet
new file mode 100644
index 0000000..fe003a3
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_next_free_othervnet_with_ipam/oldnet
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'ip' => '192.168.0.1/30',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_changeip_next_free_othervnet_with_ipam/sdn_config b/src/test/ipams/ipv4_changeip_next_free_othervnet_with_ipam/sdn_config
new file mode 100644
index 0000000..43e142f
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_next_free_othervnet_with_ipam/sdn_config
@@ -0,0 +1,35 @@
+{
+  version => 1,
+  vnets   => {
+               ids => {
+                        myvnet => { type => "vnet", zone => "myzone" },
+                        myvnet2 => { type => "vnet", zone => "myzone" },
+                        myvnet3 => { type => "vnet", zone => "myzone2" },
+                      },
+             },
+
+  zones   => {
+               ids => { 
+			myzone => { ipam => "pve", type =>"simple" },
+			myzone2 => { type =>"simple" },
+		      },
+             },
+
+  subnets => {
+              ids => { 
+			'myzone-192.168.0.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet',
+                                                  },
+			'myzone-192.168.1.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet2',
+                                                  },
+			'myzone2-192.168.2.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet3',
+                                                  },
+                     }
+
+             }
+}
diff --git a/src/test/ipams/ipv4_changeip_next_free_samevnet_with_ipam/ipam.db b/src/test/ipams/ipv4_changeip_next_free_samevnet_with_ipam/ipam.db
new file mode 100644
index 0000000..d03cc04
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_next_free_samevnet_with_ipam/ipam.db
@@ -0,0 +1,18 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+			"192.168.0.1" => {}
+		    }
+		},
+		"192.168.1.0/30" => {
+		    "ips" =>{
+		    }
+		},
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv4_changeip_next_free_samevnet_with_ipam/ipam.db.expected b/src/test/ipams/ipv4_changeip_next_free_samevnet_with_ipam/ipam.db.expected
new file mode 100644
index 0000000..2287b85
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_next_free_samevnet_with_ipam/ipam.db.expected
@@ -0,0 +1,18 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+			"192.168.0.2" => {}
+		    }
+		},
+		"192.168.1.0/30" => {
+		    "ips" =>{
+		    }
+		},
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv4_changeip_next_free_samevnet_with_ipam/ipam_config b/src/test/ipams/ipv4_changeip_next_free_samevnet_with_ipam/ipam_config
new file mode 100644
index 0000000..f5f36ad
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_next_free_samevnet_with_ipam/ipam_config
@@ -0,0 +1,7 @@
+{
+          'ids' => {
+                     'pve' => {
+                                'type' => 'pve'
+                              },
+                   },
+}
diff --git a/src/test/ipams/ipv4_changeip_next_free_samevnet_with_ipam/net b/src/test/ipams/ipv4_changeip_next_free_samevnet_with_ipam/net
new file mode 100644
index 0000000..b68d367
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_next_free_samevnet_with_ipam/net
@@ -0,0 +1,6 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_changeip_next_free_samevnet_with_ipam/net.expected b/src/test/ipams/ipv4_changeip_next_free_samevnet_with_ipam/net.expected
new file mode 100644
index 0000000..97a3915
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_next_free_samevnet_with_ipam/net.expected
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'ip' => '192.168.0.2/30',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_changeip_next_free_samevnet_with_ipam/oldnet b/src/test/ipams/ipv4_changeip_next_free_samevnet_with_ipam/oldnet
new file mode 100644
index 0000000..fe003a3
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_next_free_samevnet_with_ipam/oldnet
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'ip' => '192.168.0.1/30',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_changeip_next_free_samevnet_with_ipam/sdn_config b/src/test/ipams/ipv4_changeip_next_free_samevnet_with_ipam/sdn_config
new file mode 100644
index 0000000..43e142f
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_next_free_samevnet_with_ipam/sdn_config
@@ -0,0 +1,35 @@
+{
+  version => 1,
+  vnets   => {
+               ids => {
+                        myvnet => { type => "vnet", zone => "myzone" },
+                        myvnet2 => { type => "vnet", zone => "myzone" },
+                        myvnet3 => { type => "vnet", zone => "myzone2" },
+                      },
+             },
+
+  zones   => {
+               ids => { 
+			myzone => { ipam => "pve", type =>"simple" },
+			myzone2 => { type =>"simple" },
+		      },
+             },
+
+  subnets => {
+              ids => { 
+			'myzone-192.168.0.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet',
+                                                  },
+			'myzone-192.168.1.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet2',
+                                                  },
+			'myzone2-192.168.2.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet3',
+                                                  },
+                     }
+
+             }
+}
diff --git a/src/test/ipams/ipv4_changeip_samevnet_with_ipam/ipam.db b/src/test/ipams/ipv4_changeip_samevnet_with_ipam/ipam.db
new file mode 100644
index 0000000..d03cc04
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_samevnet_with_ipam/ipam.db
@@ -0,0 +1,18 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+			"192.168.0.1" => {}
+		    }
+		},
+		"192.168.1.0/30" => {
+		    "ips" =>{
+		    }
+		},
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv4_changeip_samevnet_with_ipam/ipam.db.expected b/src/test/ipams/ipv4_changeip_samevnet_with_ipam/ipam.db.expected
new file mode 100644
index 0000000..2287b85
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_samevnet_with_ipam/ipam.db.expected
@@ -0,0 +1,18 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+			"192.168.0.2" => {}
+		    }
+		},
+		"192.168.1.0/30" => {
+		    "ips" =>{
+		    }
+		},
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv4_changeip_samevnet_with_ipam/ipam_config b/src/test/ipams/ipv4_changeip_samevnet_with_ipam/ipam_config
new file mode 100644
index 0000000..f5f36ad
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_samevnet_with_ipam/ipam_config
@@ -0,0 +1,7 @@
+{
+          'ids' => {
+                     'pve' => {
+                                'type' => 'pve'
+                              },
+                   },
+}
diff --git a/src/test/ipams/ipv4_changeip_samevnet_with_ipam/net b/src/test/ipams/ipv4_changeip_samevnet_with_ipam/net
new file mode 100644
index 0000000..97a3915
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_samevnet_with_ipam/net
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'ip' => '192.168.0.2/30',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_changeip_samevnet_with_ipam/net.expected b/src/test/ipams/ipv4_changeip_samevnet_with_ipam/net.expected
new file mode 100644
index 0000000..97a3915
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_samevnet_with_ipam/net.expected
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'ip' => '192.168.0.2/30',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_changeip_samevnet_with_ipam/oldnet b/src/test/ipams/ipv4_changeip_samevnet_with_ipam/oldnet
new file mode 100644
index 0000000..fe003a3
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_samevnet_with_ipam/oldnet
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'ip' => '192.168.0.1/30',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_changeip_samevnet_with_ipam/sdn_config b/src/test/ipams/ipv4_changeip_samevnet_with_ipam/sdn_config
new file mode 100644
index 0000000..43e142f
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_samevnet_with_ipam/sdn_config
@@ -0,0 +1,35 @@
+{
+  version => 1,
+  vnets   => {
+               ids => {
+                        myvnet => { type => "vnet", zone => "myzone" },
+                        myvnet2 => { type => "vnet", zone => "myzone" },
+                        myvnet3 => { type => "vnet", zone => "myzone2" },
+                      },
+             },
+
+  zones   => {
+               ids => { 
+			myzone => { ipam => "pve", type =>"simple" },
+			myzone2 => { type =>"simple" },
+		      },
+             },
+
+  subnets => {
+              ids => { 
+			'myzone-192.168.0.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet',
+                                                  },
+			'myzone-192.168.1.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet2',
+                                                  },
+			'myzone2-192.168.2.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet3',
+                                                  },
+                     }
+
+             }
+}
diff --git a/src/test/ipams/ipv4_changeip_vmbr0_to_ipamvnet/ipam.db b/src/test/ipams/ipv4_changeip_vmbr0_to_ipamvnet/ipam.db
new file mode 100644
index 0000000..3d36a24
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_vmbr0_to_ipamvnet/ipam.db
@@ -0,0 +1,17 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+		    }
+		},
+		"192.168.1.0/30" => {
+		    "ips" =>{
+		    }
+		},
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv4_changeip_vmbr0_to_ipamvnet/ipam.db.expected b/src/test/ipams/ipv4_changeip_vmbr0_to_ipamvnet/ipam.db.expected
new file mode 100644
index 0000000..e0906aa
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_vmbr0_to_ipamvnet/ipam.db.expected
@@ -0,0 +1,18 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+			'192.168.0.1' => {}
+		    }
+		},
+		"192.168.1.0/30" => {
+		    "ips" =>{
+		    }
+		},
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv4_changeip_vmbr0_to_ipamvnet/ipam_config b/src/test/ipams/ipv4_changeip_vmbr0_to_ipamvnet/ipam_config
new file mode 100644
index 0000000..f5f36ad
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_vmbr0_to_ipamvnet/ipam_config
@@ -0,0 +1,7 @@
+{
+          'ids' => {
+                     'pve' => {
+                                'type' => 'pve'
+                              },
+                   },
+}
diff --git a/src/test/ipams/ipv4_changeip_vmbr0_to_ipamvnet/net b/src/test/ipams/ipv4_changeip_vmbr0_to_ipamvnet/net
new file mode 100644
index 0000000..fe003a3
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_vmbr0_to_ipamvnet/net
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'ip' => '192.168.0.1/30',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_changeip_vmbr0_to_ipamvnet/net.expected b/src/test/ipams/ipv4_changeip_vmbr0_to_ipamvnet/net.expected
new file mode 100644
index 0000000..fe003a3
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_vmbr0_to_ipamvnet/net.expected
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'ip' => '192.168.0.1/30',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_changeip_vmbr0_to_ipamvnet/oldnet b/src/test/ipams/ipv4_changeip_vmbr0_to_ipamvnet/oldnet
new file mode 100644
index 0000000..dbd70c4
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_vmbr0_to_ipamvnet/oldnet
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'vmbr0',
+    'ip' => '10.0.0.1/24',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_changeip_vmbr0_to_ipamvnet/sdn_config b/src/test/ipams/ipv4_changeip_vmbr0_to_ipamvnet/sdn_config
new file mode 100644
index 0000000..43e142f
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_vmbr0_to_ipamvnet/sdn_config
@@ -0,0 +1,35 @@
+{
+  version => 1,
+  vnets   => {
+               ids => {
+                        myvnet => { type => "vnet", zone => "myzone" },
+                        myvnet2 => { type => "vnet", zone => "myzone" },
+                        myvnet3 => { type => "vnet", zone => "myzone2" },
+                      },
+             },
+
+  zones   => {
+               ids => { 
+			myzone => { ipam => "pve", type =>"simple" },
+			myzone2 => { type =>"simple" },
+		      },
+             },
+
+  subnets => {
+              ids => { 
+			'myzone-192.168.0.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet',
+                                                  },
+			'myzone-192.168.1.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet2',
+                                                  },
+			'myzone2-192.168.2.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet3',
+                                                  },
+                     }
+
+             }
+}
diff --git a/src/test/ipams/ipv4_changeip_vmbr0_to_noipamvnet/ipam.db b/src/test/ipams/ipv4_changeip_vmbr0_to_noipamvnet/ipam.db
new file mode 100644
index 0000000..3d36a24
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_vmbr0_to_noipamvnet/ipam.db
@@ -0,0 +1,17 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+		    }
+		},
+		"192.168.1.0/30" => {
+		    "ips" =>{
+		    }
+		},
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv4_changeip_vmbr0_to_noipamvnet/ipam.db.expected b/src/test/ipams/ipv4_changeip_vmbr0_to_noipamvnet/ipam.db.expected
new file mode 100644
index 0000000..3d36a24
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_vmbr0_to_noipamvnet/ipam.db.expected
@@ -0,0 +1,17 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+		    }
+		},
+		"192.168.1.0/30" => {
+		    "ips" =>{
+		    }
+		},
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv4_changeip_vmbr0_to_noipamvnet/ipam_config b/src/test/ipams/ipv4_changeip_vmbr0_to_noipamvnet/ipam_config
new file mode 100644
index 0000000..f5f36ad
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_vmbr0_to_noipamvnet/ipam_config
@@ -0,0 +1,7 @@
+{
+          'ids' => {
+                     'pve' => {
+                                'type' => 'pve'
+                              },
+                   },
+}
diff --git a/src/test/ipams/ipv4_changeip_vmbr0_to_noipamvnet/net b/src/test/ipams/ipv4_changeip_vmbr0_to_noipamvnet/net
new file mode 100644
index 0000000..26740b4
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_vmbr0_to_noipamvnet/net
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet3',
+    'ip' => '192.168.2.1/30',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_changeip_vmbr0_to_noipamvnet/net.expected b/src/test/ipams/ipv4_changeip_vmbr0_to_noipamvnet/net.expected
new file mode 100644
index 0000000..26740b4
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_vmbr0_to_noipamvnet/net.expected
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet3',
+    'ip' => '192.168.2.1/30',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_changeip_vmbr0_to_noipamvnet/oldnet b/src/test/ipams/ipv4_changeip_vmbr0_to_noipamvnet/oldnet
new file mode 100644
index 0000000..dbd70c4
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_vmbr0_to_noipamvnet/oldnet
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'vmbr0',
+    'ip' => '10.0.0.1/24',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_changeip_vmbr0_to_noipamvnet/sdn_config b/src/test/ipams/ipv4_changeip_vmbr0_to_noipamvnet/sdn_config
new file mode 100644
index 0000000..43e142f
--- /dev/null
+++ b/src/test/ipams/ipv4_changeip_vmbr0_to_noipamvnet/sdn_config
@@ -0,0 +1,35 @@
+{
+  version => 1,
+  vnets   => {
+               ids => {
+                        myvnet => { type => "vnet", zone => "myzone" },
+                        myvnet2 => { type => "vnet", zone => "myzone" },
+                        myvnet3 => { type => "vnet", zone => "myzone2" },
+                      },
+             },
+
+  zones   => {
+               ids => { 
+			myzone => { ipam => "pve", type =>"simple" },
+			myzone2 => { type =>"simple" },
+		      },
+             },
+
+  subnets => {
+              ids => { 
+			'myzone-192.168.0.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet',
+                                                  },
+			'myzone-192.168.1.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet2',
+                                                  },
+			'myzone2-192.168.2.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet3',
+                                                  },
+                     }
+
+             }
+}
diff --git a/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetipam/ipam.db b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetipam/ipam.db
new file mode 100644
index 0000000..d03cc04
--- /dev/null
+++ b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetipam/ipam.db
@@ -0,0 +1,18 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+			"192.168.0.1" => {}
+		    }
+		},
+		"192.168.1.0/30" => {
+		    "ips" =>{
+		    }
+		},
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetipam/ipam.db.expected b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetipam/ipam.db.expected
new file mode 100644
index 0000000..f576915
--- /dev/null
+++ b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetipam/ipam.db.expected
@@ -0,0 +1,18 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+		    }
+		},
+		"192.168.1.0/30" => {
+		    "ips" =>{
+			"192.168.1.1" => {}
+		    }
+		},
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetipam/ipam_config b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetipam/ipam_config
new file mode 100644
index 0000000..f5f36ad
--- /dev/null
+++ b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetipam/ipam_config
@@ -0,0 +1,7 @@
+{
+          'ids' => {
+                     'pve' => {
+                                'type' => 'pve'
+                              },
+                   },
+}
diff --git a/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetipam/net b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetipam/net
new file mode 100644
index 0000000..4031d65
--- /dev/null
+++ b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetipam/net
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet2',
+    'ip' => '192.168.1.1/30',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetipam/net.expected b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetipam/net.expected
new file mode 100644
index 0000000..d79ce80
--- /dev/null
+++ b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetipam/net.expected
@@ -0,0 +1,8 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet2',
+    'ip' => '192.168.1.1/30',
+    'gw' => '192.168.1.2',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetipam/oldnet b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetipam/oldnet
new file mode 100644
index 0000000..fe003a3
--- /dev/null
+++ b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetipam/oldnet
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'ip' => '192.168.0.1/30',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetipam/sdn_config b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetipam/sdn_config
new file mode 100644
index 0000000..da2eded
--- /dev/null
+++ b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetipam/sdn_config
@@ -0,0 +1,38 @@
+{
+  version => 1,
+  vnets   => {
+               ids => {
+                        myvnet => { type => "vnet", zone => "myzone" },
+                        myvnet2 => { type => "vnet", zone => "myzone" },
+                        myvnet3 => { type => "vnet", zone => "myzone2" },
+                      },
+             },
+
+  zones   => {
+               ids => { 
+			myzone => { ipam => "pve", type =>"simple" },
+			myzone2 => { type =>"simple" },
+		      },
+             },
+
+  subnets => {
+              ids => { 
+			'myzone-192.168.0.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet',
+							'gateway' => '192.168.0.2'
+                                                  },
+			'myzone-192.168.1.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet2',
+							'gateway' => '192.168.1.2'
+                                                  },
+			'myzone2-192.168.2.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet3',
+							'gateway' => '192.168.2.3'
+                                                  },
+                     }
+
+             }
+}
diff --git a/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetnoipam/ipam.db b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetnoipam/ipam.db
new file mode 100644
index 0000000..d03cc04
--- /dev/null
+++ b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetnoipam/ipam.db
@@ -0,0 +1,18 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+			"192.168.0.1" => {}
+		    }
+		},
+		"192.168.1.0/30" => {
+		    "ips" =>{
+		    }
+		},
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetnoipam/ipam.db.expected b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetnoipam/ipam.db.expected
new file mode 100644
index 0000000..3d36a24
--- /dev/null
+++ b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetnoipam/ipam.db.expected
@@ -0,0 +1,17 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+		    }
+		},
+		"192.168.1.0/30" => {
+		    "ips" =>{
+		    }
+		},
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetnoipam/ipam_config b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetnoipam/ipam_config
new file mode 100644
index 0000000..f5f36ad
--- /dev/null
+++ b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetnoipam/ipam_config
@@ -0,0 +1,7 @@
+{
+          'ids' => {
+                     'pve' => {
+                                'type' => 'pve'
+                              },
+                   },
+}
diff --git a/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetnoipam/net b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetnoipam/net
new file mode 100644
index 0000000..ae2b7bc
--- /dev/null
+++ b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetnoipam/net
@@ -0,0 +1,8 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet3',
+    'ip' => '192.168.2.1/30',
+    'gw' => '192.168.2.2',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetnoipam/net.expected b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetnoipam/net.expected
new file mode 100644
index 0000000..ae2b7bc
--- /dev/null
+++ b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetnoipam/net.expected
@@ -0,0 +1,8 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet3',
+    'ip' => '192.168.2.1/30',
+    'gw' => '192.168.2.2',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetnoipam/oldnet b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetnoipam/oldnet
new file mode 100644
index 0000000..fe003a3
--- /dev/null
+++ b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetnoipam/oldnet
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'ip' => '192.168.0.1/30',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetnoipam/sdn_config b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetnoipam/sdn_config
new file mode 100644
index 0000000..56b17ae
--- /dev/null
+++ b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_gateway_othervnetnoipam/sdn_config
@@ -0,0 +1,38 @@
+{
+  version => 1,
+  vnets   => {
+               ids => {
+                        myvnet => { type => "vnet", zone => "myzone" },
+                        myvnet2 => { type => "vnet", zone => "myzone" },
+                        myvnet3 => { type => "vnet", zone => "myzone2" },
+                      },
+             },
+
+  zones   => {
+               ids => { 
+			myzone => { ipam => "pve", type =>"simple" },
+			myzone2 => { type =>"simple" },
+		      },
+             },
+
+  subnets => {
+              ids => { 
+			'myzone-192.168.0.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet',
+							'gateway' => '192.168.0.2'
+                                                  },
+			'myzone-192.168.1.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet2',
+							'gateway' => '192.168.1.2'
+                                                  },
+			'myzone2-192.168.2.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet3',
+							'gateway' => '192.168.2.2'
+                                                  },
+                     }
+
+             }
+}
diff --git a/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_nogateway_othervnetipam/ipam.db b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_nogateway_othervnetipam/ipam.db
new file mode 100644
index 0000000..d03cc04
--- /dev/null
+++ b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_nogateway_othervnetipam/ipam.db
@@ -0,0 +1,18 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+			"192.168.0.1" => {}
+		    }
+		},
+		"192.168.1.0/30" => {
+		    "ips" =>{
+		    }
+		},
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_nogateway_othervnetipam/ipam.db.expected b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_nogateway_othervnetipam/ipam.db.expected
new file mode 100644
index 0000000..f576915
--- /dev/null
+++ b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_nogateway_othervnetipam/ipam.db.expected
@@ -0,0 +1,18 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+		    }
+		},
+		"192.168.1.0/30" => {
+		    "ips" =>{
+			"192.168.1.1" => {}
+		    }
+		},
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_nogateway_othervnetipam/ipam_config b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_nogateway_othervnetipam/ipam_config
new file mode 100644
index 0000000..f5f36ad
--- /dev/null
+++ b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_nogateway_othervnetipam/ipam_config
@@ -0,0 +1,7 @@
+{
+          'ids' => {
+                     'pve' => {
+                                'type' => 'pve'
+                              },
+                   },
+}
diff --git a/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_nogateway_othervnetipam/net b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_nogateway_othervnetipam/net
new file mode 100644
index 0000000..4031d65
--- /dev/null
+++ b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_nogateway_othervnetipam/net
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet2',
+    'ip' => '192.168.1.1/30',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_nogateway_othervnetipam/net.expected b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_nogateway_othervnetipam/net.expected
new file mode 100644
index 0000000..4031d65
--- /dev/null
+++ b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_nogateway_othervnetipam/net.expected
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet2',
+    'ip' => '192.168.1.1/30',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_nogateway_othervnetipam/oldnet b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_nogateway_othervnetipam/oldnet
new file mode 100644
index 0000000..e3e093c
--- /dev/null
+++ b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_nogateway_othervnetipam/oldnet
@@ -0,0 +1,8 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'ip' => '192.168.0.1/30',
+    'gw' => '192.168.0.2',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_nogateway_othervnetipam/sdn_config b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_nogateway_othervnetipam/sdn_config
new file mode 100644
index 0000000..20785d0
--- /dev/null
+++ b/src/test/ipams/ipv4_gateway_changeip_ipamvnet_to_nogateway_othervnetipam/sdn_config
@@ -0,0 +1,36 @@
+{
+  version => 1,
+  vnets   => {
+               ids => {
+                        myvnet => { type => "vnet", zone => "myzone" },
+                        myvnet2 => { type => "vnet", zone => "myzone" },
+                        myvnet3 => { type => "vnet", zone => "myzone2" },
+                      },
+             },
+
+  zones   => {
+               ids => { 
+			myzone => { ipam => "pve", type =>"simple" },
+			myzone2 => { type =>"simple" },
+		      },
+             },
+
+  subnets => {
+              ids => { 
+			'myzone-192.168.0.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet',
+							'gateway' => '192.168.0.2'
+                                                  },
+			'myzone-192.168.1.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet2',
+                                                  },
+			'myzone2-192.168.2.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet3',
+                                                  },
+                     }
+
+             }
+}
diff --git a/src/test/ipams/ipv4_updateipam_ipamvnet/ipam.db b/src/test/ipams/ipv4_updateipam_ipamvnet/ipam.db
new file mode 100644
index 0000000..d03cc04
--- /dev/null
+++ b/src/test/ipams/ipv4_updateipam_ipamvnet/ipam.db
@@ -0,0 +1,18 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+			"192.168.0.1" => {}
+		    }
+		},
+		"192.168.1.0/30" => {
+		    "ips" =>{
+		    }
+		},
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv4_updateipam_ipamvnet/ipam.db.expected b/src/test/ipams/ipv4_updateipam_ipamvnet/ipam.db.expected
new file mode 100644
index 0000000..d03cc04
--- /dev/null
+++ b/src/test/ipams/ipv4_updateipam_ipamvnet/ipam.db.expected
@@ -0,0 +1,18 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+			"192.168.0.1" => {}
+		    }
+		},
+		"192.168.1.0/30" => {
+		    "ips" =>{
+		    }
+		},
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv4_updateipam_ipamvnet/ipam_config b/src/test/ipams/ipv4_updateipam_ipamvnet/ipam_config
new file mode 100644
index 0000000..f5f36ad
--- /dev/null
+++ b/src/test/ipams/ipv4_updateipam_ipamvnet/ipam_config
@@ -0,0 +1,7 @@
+{
+          'ids' => {
+                     'pve' => {
+                                'type' => 'pve'
+                              },
+                   },
+}
diff --git a/src/test/ipams/ipv4_updateipam_ipamvnet/net b/src/test/ipams/ipv4_updateipam_ipamvnet/net
new file mode 100644
index 0000000..fe003a3
--- /dev/null
+++ b/src/test/ipams/ipv4_updateipam_ipamvnet/net
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'ip' => '192.168.0.1/30',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_updateipam_ipamvnet/net.expected b/src/test/ipams/ipv4_updateipam_ipamvnet/net.expected
new file mode 100644
index 0000000..fe003a3
--- /dev/null
+++ b/src/test/ipams/ipv4_updateipam_ipamvnet/net.expected
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'ip' => '192.168.0.1/30',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_updateipam_ipamvnet/oldnet b/src/test/ipams/ipv4_updateipam_ipamvnet/oldnet
new file mode 100644
index 0000000..fe003a3
--- /dev/null
+++ b/src/test/ipams/ipv4_updateipam_ipamvnet/oldnet
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'ip' => '192.168.0.1/30',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4_updateipam_ipamvnet/sdn_config b/src/test/ipams/ipv4_updateipam_ipamvnet/sdn_config
new file mode 100644
index 0000000..43e142f
--- /dev/null
+++ b/src/test/ipams/ipv4_updateipam_ipamvnet/sdn_config
@@ -0,0 +1,35 @@
+{
+  version => 1,
+  vnets   => {
+               ids => {
+                        myvnet => { type => "vnet", zone => "myzone" },
+                        myvnet2 => { type => "vnet", zone => "myzone" },
+                        myvnet3 => { type => "vnet", zone => "myzone2" },
+                      },
+             },
+
+  zones   => {
+               ids => { 
+			myzone => { ipam => "pve", type =>"simple" },
+			myzone2 => { type =>"simple" },
+		      },
+             },
+
+  subnets => {
+              ids => { 
+			'myzone-192.168.0.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet',
+                                                  },
+			'myzone-192.168.1.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet2',
+                                                  },
+			'myzone2-192.168.2.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet3',
+                                                  },
+                     }
+
+             }
+}
diff --git a/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam/ipam.db b/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam/ipam.db
new file mode 100644
index 0000000..252c95a
--- /dev/null
+++ b/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam/ipam.db
@@ -0,0 +1,19 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+			"192.168.0.1" => {}
+		    }
+		},
+                "2001:db8:85a3::8a2e:370:7334/127" => {
+                    "ips" =>{
+			"2001:db8:85a3::8a2e:370:7334" => {}
+                    }
+                },
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam/ipam.db.expected b/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam/ipam.db.expected
new file mode 100644
index 0000000..8dcf09b
--- /dev/null
+++ b/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam/ipam.db.expected
@@ -0,0 +1,19 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+			"192.168.0.2" => {}
+		    }
+		},
+                "2001:db8:85a3::8a2e:370:7334/127" => {
+                    "ips" =>{
+			"2001:db8:85a3::8a2e:370:7335" => {}
+                    }
+                },
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam/ipam_config b/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam/ipam_config
new file mode 100644
index 0000000..f5f36ad
--- /dev/null
+++ b/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam/ipam_config
@@ -0,0 +1,7 @@
+{
+          'ids' => {
+                     'pve' => {
+                                'type' => 'pve'
+                              },
+                   },
+}
diff --git a/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam/net b/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam/net
new file mode 100644
index 0000000..b68d367
--- /dev/null
+++ b/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam/net
@@ -0,0 +1,6 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam/net.expected b/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam/net.expected
new file mode 100644
index 0000000..3b6e3c5
--- /dev/null
+++ b/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam/net.expected
@@ -0,0 +1,8 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'ip' => '192.168.0.2/30',
+    'ip6' => '2001:db8:85a3::8a2e:370:7335/127',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam/oldnet b/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam/oldnet
new file mode 100644
index 0000000..929f90d
--- /dev/null
+++ b/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam/oldnet
@@ -0,0 +1,8 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'ip' => '192.168.0.1/30',
+    'ip6' => '2001:db8:85a3::8a2e:370:7334/127',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam/sdn_config b/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam/sdn_config
new file mode 100644
index 0000000..171cb08
--- /dev/null
+++ b/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam/sdn_config
@@ -0,0 +1,39 @@
+{
+  version => 1,
+  vnets   => {
+               ids => {
+                        myvnet => { type => "vnet", zone => "myzone" },
+                        myvnet2 => { type => "vnet", zone => "myzone" },
+                        myvnet3 => { type => "vnet", zone => "myzone2" },
+                      },
+             },
+
+  zones   => {
+               ids => { 
+			myzone => { ipam => "pve", type =>"simple" },
+			myzone2 => { type =>"simple" },
+		      },
+             },
+
+  subnets => {
+              ids => { 
+			'myzone-192.168.0.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet',
+                                                  },
+			'myzone-2001:db8:85a3::8a2e:370:7334-127' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet',
+                                                  },
+			'myzone-192.168.1.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet2',
+                                                  },
+			'myzone2-192.168.2.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet3',
+                                                  },
+                     }
+
+             }
+}
diff --git a/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam_failingv6/ipam.db b/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam_failingv6/ipam.db
new file mode 100644
index 0000000..de920d7
--- /dev/null
+++ b/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam_failingv6/ipam.db
@@ -0,0 +1,20 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+			"192.168.0.1" => {}
+		    }
+		},
+                "2001:db8:85a3::8a2e:370:7334/127" => {
+                    "ips" =>{
+			"2001:db8:85a3::8a2e:370:7334" => {},
+			"2001:db8:85a3::8a2e:370:7335" => {}
+                    }
+                },
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam_failingv6/ipam.db.expected b/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam_failingv6/ipam.db.expected
new file mode 100644
index 0000000..de920d7
--- /dev/null
+++ b/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam_failingv6/ipam.db.expected
@@ -0,0 +1,20 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+			"192.168.0.1" => {}
+		    }
+		},
+                "2001:db8:85a3::8a2e:370:7334/127" => {
+                    "ips" =>{
+			"2001:db8:85a3::8a2e:370:7334" => {},
+			"2001:db8:85a3::8a2e:370:7335" => {}
+                    }
+                },
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam_failingv6/ipam_config b/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam_failingv6/ipam_config
new file mode 100644
index 0000000..f5f36ad
--- /dev/null
+++ b/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam_failingv6/ipam_config
@@ -0,0 +1,7 @@
+{
+          'ids' => {
+                     'pve' => {
+                                'type' => 'pve'
+                              },
+                   },
+}
diff --git a/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam_failingv6/net b/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam_failingv6/net
new file mode 100644
index 0000000..b68d367
--- /dev/null
+++ b/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam_failingv6/net
@@ -0,0 +1,6 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam_failingv6/net.expected b/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam_failingv6/net.expected
new file mode 100644
index 0000000..929f90d
--- /dev/null
+++ b/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam_failingv6/net.expected
@@ -0,0 +1,8 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'ip' => '192.168.0.1/30',
+    'ip6' => '2001:db8:85a3::8a2e:370:7334/127',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam_failingv6/oldnet b/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam_failingv6/oldnet
new file mode 100644
index 0000000..929f90d
--- /dev/null
+++ b/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam_failingv6/oldnet
@@ -0,0 +1,8 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'ip' => '192.168.0.1/30',
+    'ip6' => '2001:db8:85a3::8a2e:370:7334/127',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam_failingv6/sdn_config b/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam_failingv6/sdn_config
new file mode 100644
index 0000000..171cb08
--- /dev/null
+++ b/src/test/ipams/ipv4v6_next_free_samevnet_with_ipam_failingv6/sdn_config
@@ -0,0 +1,39 @@
+{
+  version => 1,
+  vnets   => {
+               ids => {
+                        myvnet => { type => "vnet", zone => "myzone" },
+                        myvnet2 => { type => "vnet", zone => "myzone" },
+                        myvnet3 => { type => "vnet", zone => "myzone2" },
+                      },
+             },
+
+  zones   => {
+               ids => { 
+			myzone => { ipam => "pve", type =>"simple" },
+			myzone2 => { type =>"simple" },
+		      },
+             },
+
+  subnets => {
+              ids => { 
+			'myzone-192.168.0.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet',
+                                                  },
+			'myzone-2001:db8:85a3::8a2e:370:7334-127' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet',
+                                                  },
+			'myzone-192.168.1.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet2',
+                                                  },
+			'myzone2-192.168.2.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet3',
+                                                  },
+                     }
+
+             }
+}
diff --git a/src/test/ipams/ipv4v6_updateipam_ipamvnet/ipam.db b/src/test/ipams/ipv4v6_updateipam_ipamvnet/ipam.db
new file mode 100644
index 0000000..252c95a
--- /dev/null
+++ b/src/test/ipams/ipv4v6_updateipam_ipamvnet/ipam.db
@@ -0,0 +1,19 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+			"192.168.0.1" => {}
+		    }
+		},
+                "2001:db8:85a3::8a2e:370:7334/127" => {
+                    "ips" =>{
+			"2001:db8:85a3::8a2e:370:7334" => {}
+                    }
+                },
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv4v6_updateipam_ipamvnet/ipam.db.expected b/src/test/ipams/ipv4v6_updateipam_ipamvnet/ipam.db.expected
new file mode 100644
index 0000000..adb6fc7
--- /dev/null
+++ b/src/test/ipams/ipv4v6_updateipam_ipamvnet/ipam.db.expected
@@ -0,0 +1,19 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+			"192.168.0.1" => {}
+		    }
+		},
+                "2001:db8:85a3::8a2e:370:7334/127" => {
+                    "ips" =>{
+			"2001:db8:85a3::8a2e:370:7335" => {}
+                    }
+                },
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv4v6_updateipam_ipamvnet/ipam_config b/src/test/ipams/ipv4v6_updateipam_ipamvnet/ipam_config
new file mode 100644
index 0000000..f5f36ad
--- /dev/null
+++ b/src/test/ipams/ipv4v6_updateipam_ipamvnet/ipam_config
@@ -0,0 +1,7 @@
+{
+          'ids' => {
+                     'pve' => {
+                                'type' => 'pve'
+                              },
+                   },
+}
diff --git a/src/test/ipams/ipv4v6_updateipam_ipamvnet/net b/src/test/ipams/ipv4v6_updateipam_ipamvnet/net
new file mode 100644
index 0000000..e7052bc
--- /dev/null
+++ b/src/test/ipams/ipv4v6_updateipam_ipamvnet/net
@@ -0,0 +1,8 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'ip' => '192.168.0.1/30',
+    'ip6' => '2001:db8:85a3::8a2e:370:7335/127',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4v6_updateipam_ipamvnet/net.expected b/src/test/ipams/ipv4v6_updateipam_ipamvnet/net.expected
new file mode 100644
index 0000000..e7052bc
--- /dev/null
+++ b/src/test/ipams/ipv4v6_updateipam_ipamvnet/net.expected
@@ -0,0 +1,8 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'ip' => '192.168.0.1/30',
+    'ip6' => '2001:db8:85a3::8a2e:370:7335/127',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4v6_updateipam_ipamvnet/oldnet b/src/test/ipams/ipv4v6_updateipam_ipamvnet/oldnet
new file mode 100644
index 0000000..929f90d
--- /dev/null
+++ b/src/test/ipams/ipv4v6_updateipam_ipamvnet/oldnet
@@ -0,0 +1,8 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'ip' => '192.168.0.1/30',
+    'ip6' => '2001:db8:85a3::8a2e:370:7334/127',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4v6_updateipam_ipamvnet/sdn_config b/src/test/ipams/ipv4v6_updateipam_ipamvnet/sdn_config
new file mode 100644
index 0000000..171cb08
--- /dev/null
+++ b/src/test/ipams/ipv4v6_updateipam_ipamvnet/sdn_config
@@ -0,0 +1,39 @@
+{
+  version => 1,
+  vnets   => {
+               ids => {
+                        myvnet => { type => "vnet", zone => "myzone" },
+                        myvnet2 => { type => "vnet", zone => "myzone" },
+                        myvnet3 => { type => "vnet", zone => "myzone2" },
+                      },
+             },
+
+  zones   => {
+               ids => { 
+			myzone => { ipam => "pve", type =>"simple" },
+			myzone2 => { type =>"simple" },
+		      },
+             },
+
+  subnets => {
+              ids => { 
+			'myzone-192.168.0.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet',
+                                                  },
+			'myzone-2001:db8:85a3::8a2e:370:7334-127' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet',
+                                                  },
+			'myzone-192.168.1.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet2',
+                                                  },
+			'myzone2-192.168.2.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet3',
+                                                  },
+                     }
+
+             }
+}
diff --git a/src/test/ipams/ipv4v6_updateipam_ipamvnet_failingv6/ipam.db b/src/test/ipams/ipv4v6_updateipam_ipamvnet_failingv6/ipam.db
new file mode 100644
index 0000000..252c95a
--- /dev/null
+++ b/src/test/ipams/ipv4v6_updateipam_ipamvnet_failingv6/ipam.db
@@ -0,0 +1,19 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+			"192.168.0.1" => {}
+		    }
+		},
+                "2001:db8:85a3::8a2e:370:7334/127" => {
+                    "ips" =>{
+			"2001:db8:85a3::8a2e:370:7334" => {}
+                    }
+                },
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv4v6_updateipam_ipamvnet_failingv6/ipam.db.expected b/src/test/ipams/ipv4v6_updateipam_ipamvnet_failingv6/ipam.db.expected
new file mode 100644
index 0000000..252c95a
--- /dev/null
+++ b/src/test/ipams/ipv4v6_updateipam_ipamvnet_failingv6/ipam.db.expected
@@ -0,0 +1,19 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+			"192.168.0.1" => {}
+		    }
+		},
+                "2001:db8:85a3::8a2e:370:7334/127" => {
+                    "ips" =>{
+			"2001:db8:85a3::8a2e:370:7334" => {}
+                    }
+                },
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv4v6_updateipam_ipamvnet_failingv6/ipam_config b/src/test/ipams/ipv4v6_updateipam_ipamvnet_failingv6/ipam_config
new file mode 100644
index 0000000..f5f36ad
--- /dev/null
+++ b/src/test/ipams/ipv4v6_updateipam_ipamvnet_failingv6/ipam_config
@@ -0,0 +1,7 @@
+{
+          'ids' => {
+                     'pve' => {
+                                'type' => 'pve'
+                              },
+                   },
+}
diff --git a/src/test/ipams/ipv4v6_updateipam_ipamvnet_failingv6/net b/src/test/ipams/ipv4v6_updateipam_ipamvnet_failingv6/net
new file mode 100644
index 0000000..872a354
--- /dev/null
+++ b/src/test/ipams/ipv4v6_updateipam_ipamvnet_failingv6/net
@@ -0,0 +1,8 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'ip' => '192.168.0.1/30',
+    'ip6' => '2001:db8:85a3::8a2e:370:7336/127',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4v6_updateipam_ipamvnet_failingv6/net.expected b/src/test/ipams/ipv4v6_updateipam_ipamvnet_failingv6/net.expected
new file mode 100644
index 0000000..929f90d
--- /dev/null
+++ b/src/test/ipams/ipv4v6_updateipam_ipamvnet_failingv6/net.expected
@@ -0,0 +1,8 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'ip' => '192.168.0.1/30',
+    'ip6' => '2001:db8:85a3::8a2e:370:7334/127',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4v6_updateipam_ipamvnet_failingv6/oldnet b/src/test/ipams/ipv4v6_updateipam_ipamvnet_failingv6/oldnet
new file mode 100644
index 0000000..929f90d
--- /dev/null
+++ b/src/test/ipams/ipv4v6_updateipam_ipamvnet_failingv6/oldnet
@@ -0,0 +1,8 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'ip' => '192.168.0.1/30',
+    'ip6' => '2001:db8:85a3::8a2e:370:7334/127',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv4v6_updateipam_ipamvnet_failingv6/sdn_config b/src/test/ipams/ipv4v6_updateipam_ipamvnet_failingv6/sdn_config
new file mode 100644
index 0000000..43e142f
--- /dev/null
+++ b/src/test/ipams/ipv4v6_updateipam_ipamvnet_failingv6/sdn_config
@@ -0,0 +1,35 @@
+{
+  version => 1,
+  vnets   => {
+               ids => {
+                        myvnet => { type => "vnet", zone => "myzone" },
+                        myvnet2 => { type => "vnet", zone => "myzone" },
+                        myvnet3 => { type => "vnet", zone => "myzone2" },
+                      },
+             },
+
+  zones   => {
+               ids => { 
+			myzone => { ipam => "pve", type =>"simple" },
+			myzone2 => { type =>"simple" },
+		      },
+             },
+
+  subnets => {
+              ids => { 
+			'myzone-192.168.0.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet',
+                                                  },
+			'myzone-192.168.1.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet2',
+                                                  },
+			'myzone2-192.168.2.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet3',
+                                                  },
+                     }
+
+             }
+}
diff --git a/src/test/ipams/ipv6_changeip_ipamvnet_to_othervnetipam/ipam.db b/src/test/ipams/ipv6_changeip_ipamvnet_to_othervnetipam/ipam.db
new file mode 100644
index 0000000..16c5af3
--- /dev/null
+++ b/src/test/ipams/ipv6_changeip_ipamvnet_to_othervnetipam/ipam.db
@@ -0,0 +1,18 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+                "2001:db8:85a3::8a2e:370:7334/127" => {
+                    "ips" =>{
+			"2001:db8:85a3::8a2e:370:7334" => {}
+                    }
+                },
+                "2001:db8:85a3::8a2e:371:7334/127" => {
+                    "ips" =>{
+                    }
+                },
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv6_changeip_ipamvnet_to_othervnetipam/ipam.db.expected b/src/test/ipams/ipv6_changeip_ipamvnet_to_othervnetipam/ipam.db.expected
new file mode 100644
index 0000000..4039793
--- /dev/null
+++ b/src/test/ipams/ipv6_changeip_ipamvnet_to_othervnetipam/ipam.db.expected
@@ -0,0 +1,18 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+                "2001:db8:85a3::8a2e:370:7334/127" => {
+                    "ips" =>{
+                    }
+                },
+                "2001:db8:85a3::8a2e:371:7334/127" => {
+                    "ips" =>{
+			"2001:db8:85a3::8a2e:371:7334" => {}
+                    }
+                },
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv6_changeip_ipamvnet_to_othervnetipam/ipam_config b/src/test/ipams/ipv6_changeip_ipamvnet_to_othervnetipam/ipam_config
new file mode 100644
index 0000000..f5f36ad
--- /dev/null
+++ b/src/test/ipams/ipv6_changeip_ipamvnet_to_othervnetipam/ipam_config
@@ -0,0 +1,7 @@
+{
+          'ids' => {
+                     'pve' => {
+                                'type' => 'pve'
+                              },
+                   },
+}
diff --git a/src/test/ipams/ipv6_changeip_ipamvnet_to_othervnetipam/net b/src/test/ipams/ipv6_changeip_ipamvnet_to_othervnetipam/net
new file mode 100644
index 0000000..b4bee3a
--- /dev/null
+++ b/src/test/ipams/ipv6_changeip_ipamvnet_to_othervnetipam/net
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet2',
+    'ip6' => '2001:db8:85a3::8a2e:371:7334/127',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv6_changeip_ipamvnet_to_othervnetipam/net.expected b/src/test/ipams/ipv6_changeip_ipamvnet_to_othervnetipam/net.expected
new file mode 100644
index 0000000..b4bee3a
--- /dev/null
+++ b/src/test/ipams/ipv6_changeip_ipamvnet_to_othervnetipam/net.expected
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet2',
+    'ip6' => '2001:db8:85a3::8a2e:371:7334/127',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv6_changeip_ipamvnet_to_othervnetipam/oldnet b/src/test/ipams/ipv6_changeip_ipamvnet_to_othervnetipam/oldnet
new file mode 100644
index 0000000..b1c5472
--- /dev/null
+++ b/src/test/ipams/ipv6_changeip_ipamvnet_to_othervnetipam/oldnet
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'ip6' => '2001:db8:85a3::8a2e:370:7334/127',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv6_changeip_ipamvnet_to_othervnetipam/sdn_config b/src/test/ipams/ipv6_changeip_ipamvnet_to_othervnetipam/sdn_config
new file mode 100644
index 0000000..5d48a4e
--- /dev/null
+++ b/src/test/ipams/ipv6_changeip_ipamvnet_to_othervnetipam/sdn_config
@@ -0,0 +1,35 @@
+{
+  version => 1,
+  vnets   => {
+               ids => {
+                        myvnet => { type => "vnet", zone => "myzone" },
+                        myvnet2 => { type => "vnet", zone => "myzone" },
+                        myvnet3 => { type => "vnet", zone => "myzone2" },
+                      },
+             },
+
+  zones   => {
+               ids => { 
+			myzone => { ipam => "pve", type =>"simple" },
+			myzone2 => { type =>"simple" },
+		      },
+             },
+
+  subnets => {
+              ids => { 
+			'myzone-2001:db8:85a3::8a2e:370:7334-127' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet',
+                                                  },
+			'myzone-2001:db8:85a3::8a2e:371:7334-127' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet2',
+                                                  },
+			'myzone2-2001:db8:85a3::8a2e:372:7334-127' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet3',
+                                                  },
+                     }
+
+             }
+}
diff --git a/src/test/ipams/ipv6_gateway_changeip_ipamvnet_to_gateway_othervnetipam/ipam.db b/src/test/ipams/ipv6_gateway_changeip_ipamvnet_to_gateway_othervnetipam/ipam.db
new file mode 100644
index 0000000..16c5af3
--- /dev/null
+++ b/src/test/ipams/ipv6_gateway_changeip_ipamvnet_to_gateway_othervnetipam/ipam.db
@@ -0,0 +1,18 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+                "2001:db8:85a3::8a2e:370:7334/127" => {
+                    "ips" =>{
+			"2001:db8:85a3::8a2e:370:7334" => {}
+                    }
+                },
+                "2001:db8:85a3::8a2e:371:7334/127" => {
+                    "ips" =>{
+                    }
+                },
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv6_gateway_changeip_ipamvnet_to_gateway_othervnetipam/ipam.db.expected b/src/test/ipams/ipv6_gateway_changeip_ipamvnet_to_gateway_othervnetipam/ipam.db.expected
new file mode 100644
index 0000000..4039793
--- /dev/null
+++ b/src/test/ipams/ipv6_gateway_changeip_ipamvnet_to_gateway_othervnetipam/ipam.db.expected
@@ -0,0 +1,18 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+                "2001:db8:85a3::8a2e:370:7334/127" => {
+                    "ips" =>{
+                    }
+                },
+                "2001:db8:85a3::8a2e:371:7334/127" => {
+                    "ips" =>{
+			"2001:db8:85a3::8a2e:371:7334" => {}
+                    }
+                },
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv6_gateway_changeip_ipamvnet_to_gateway_othervnetipam/ipam_config b/src/test/ipams/ipv6_gateway_changeip_ipamvnet_to_gateway_othervnetipam/ipam_config
new file mode 100644
index 0000000..f5f36ad
--- /dev/null
+++ b/src/test/ipams/ipv6_gateway_changeip_ipamvnet_to_gateway_othervnetipam/ipam_config
@@ -0,0 +1,7 @@
+{
+          'ids' => {
+                     'pve' => {
+                                'type' => 'pve'
+                              },
+                   },
+}
diff --git a/src/test/ipams/ipv6_gateway_changeip_ipamvnet_to_gateway_othervnetipam/net b/src/test/ipams/ipv6_gateway_changeip_ipamvnet_to_gateway_othervnetipam/net
new file mode 100644
index 0000000..b4bee3a
--- /dev/null
+++ b/src/test/ipams/ipv6_gateway_changeip_ipamvnet_to_gateway_othervnetipam/net
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet2',
+    'ip6' => '2001:db8:85a3::8a2e:371:7334/127',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv6_gateway_changeip_ipamvnet_to_gateway_othervnetipam/net.expected b/src/test/ipams/ipv6_gateway_changeip_ipamvnet_to_gateway_othervnetipam/net.expected
new file mode 100644
index 0000000..689f7cc
--- /dev/null
+++ b/src/test/ipams/ipv6_gateway_changeip_ipamvnet_to_gateway_othervnetipam/net.expected
@@ -0,0 +1,8 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet2',
+    'gw6' => '2001:db8:85a3::8a2e:371:7335',
+    'ip6' => '2001:db8:85a3::8a2e:371:7334/127',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv6_gateway_changeip_ipamvnet_to_gateway_othervnetipam/oldnet b/src/test/ipams/ipv6_gateway_changeip_ipamvnet_to_gateway_othervnetipam/oldnet
new file mode 100644
index 0000000..b1c5472
--- /dev/null
+++ b/src/test/ipams/ipv6_gateway_changeip_ipamvnet_to_gateway_othervnetipam/oldnet
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'ip6' => '2001:db8:85a3::8a2e:370:7334/127',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv6_gateway_changeip_ipamvnet_to_gateway_othervnetipam/sdn_config b/src/test/ipams/ipv6_gateway_changeip_ipamvnet_to_gateway_othervnetipam/sdn_config
new file mode 100644
index 0000000..3652eca
--- /dev/null
+++ b/src/test/ipams/ipv6_gateway_changeip_ipamvnet_to_gateway_othervnetipam/sdn_config
@@ -0,0 +1,37 @@
+{
+  version => 1,
+  vnets   => {
+               ids => {
+                        myvnet => { type => "vnet", zone => "myzone" },
+                        myvnet2 => { type => "vnet", zone => "myzone" },
+                        myvnet3 => { type => "vnet", zone => "myzone2" },
+                      },
+             },
+
+  zones   => {
+               ids => { 
+			myzone => { ipam => "pve", type =>"simple" },
+			myzone2 => { type =>"simple" },
+		      },
+             },
+
+  subnets => {
+              ids => { 
+			'myzone-2001:db8:85a3::8a2e:370:7334-127' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet',
+							'gateway' => '2001:db8:85a3::8a2e:370:7335'
+                                                  },
+			'myzone-2001:db8:85a3::8a2e:371:7334-127' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet2',
+							'gateway' => '2001:db8:85a3::8a2e:371:7335'
+                                                  },
+			'myzone2-2001:db8:85a3::8a2e:372:7334-127' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet3',
+                                                  },
+                     }
+
+             }
+}
diff --git a/src/test/ipams/ipv6_updateipam_ipamvnet/ipam.db b/src/test/ipams/ipv6_updateipam_ipamvnet/ipam.db
new file mode 100644
index 0000000..d8e3ce5
--- /dev/null
+++ b/src/test/ipams/ipv6_updateipam_ipamvnet/ipam.db
@@ -0,0 +1,14 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+                "2001:db8:85a3::8a2e:370:7334/127" => {
+                    "ips" =>{
+			"2001:db8:85a3::8a2e:370:7334" => {}
+                    }
+                },
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv6_updateipam_ipamvnet/ipam.db.expected b/src/test/ipams/ipv6_updateipam_ipamvnet/ipam.db.expected
new file mode 100644
index 0000000..89b6e8c
--- /dev/null
+++ b/src/test/ipams/ipv6_updateipam_ipamvnet/ipam.db.expected
@@ -0,0 +1,14 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+                "2001:db8:85a3::8a2e:370:7334/127" => {
+                    "ips" =>{
+			"2001:db8:85a3::8a2e:370:7335" => {}
+                    }
+                },
+	    }
+	},
+    }
+}
+
diff --git a/src/test/ipams/ipv6_updateipam_ipamvnet/ipam_config b/src/test/ipams/ipv6_updateipam_ipamvnet/ipam_config
new file mode 100644
index 0000000..f5f36ad
--- /dev/null
+++ b/src/test/ipams/ipv6_updateipam_ipamvnet/ipam_config
@@ -0,0 +1,7 @@
+{
+          'ids' => {
+                     'pve' => {
+                                'type' => 'pve'
+                              },
+                   },
+}
diff --git a/src/test/ipams/ipv6_updateipam_ipamvnet/net b/src/test/ipams/ipv6_updateipam_ipamvnet/net
new file mode 100644
index 0000000..4f83ab2
--- /dev/null
+++ b/src/test/ipams/ipv6_updateipam_ipamvnet/net
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'ip6' => '2001:db8:85a3::8a2e:370:7335/127',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv6_updateipam_ipamvnet/net.expected b/src/test/ipams/ipv6_updateipam_ipamvnet/net.expected
new file mode 100644
index 0000000..4f83ab2
--- /dev/null
+++ b/src/test/ipams/ipv6_updateipam_ipamvnet/net.expected
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'ip6' => '2001:db8:85a3::8a2e:370:7335/127',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv6_updateipam_ipamvnet/oldnet b/src/test/ipams/ipv6_updateipam_ipamvnet/oldnet
new file mode 100644
index 0000000..b1c5472
--- /dev/null
+++ b/src/test/ipams/ipv6_updateipam_ipamvnet/oldnet
@@ -0,0 +1,7 @@
+{
+    'name' => 'eth0',
+    'bridge' => 'myvnet',
+    'ip6' => '2001:db8:85a3::8a2e:370:7334/127',
+    'type' => 'veth',
+    'hwaddr' => '8A:4C:75:11:58:1D'
+}
diff --git a/src/test/ipams/ipv6_updateipam_ipamvnet/sdn_config b/src/test/ipams/ipv6_updateipam_ipamvnet/sdn_config
new file mode 100644
index 0000000..5d48a4e
--- /dev/null
+++ b/src/test/ipams/ipv6_updateipam_ipamvnet/sdn_config
@@ -0,0 +1,35 @@
+{
+  version => 1,
+  vnets   => {
+               ids => {
+                        myvnet => { type => "vnet", zone => "myzone" },
+                        myvnet2 => { type => "vnet", zone => "myzone" },
+                        myvnet3 => { type => "vnet", zone => "myzone2" },
+                      },
+             },
+
+  zones   => {
+               ids => { 
+			myzone => { ipam => "pve", type =>"simple" },
+			myzone2 => { type =>"simple" },
+		      },
+             },
+
+  subnets => {
+              ids => { 
+			'myzone-2001:db8:85a3::8a2e:370:7334-127' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet',
+                                                  },
+			'myzone-2001:db8:85a3::8a2e:371:7334-127' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet2',
+                                                  },
+			'myzone2-2001:db8:85a3::8a2e:372:7334-127' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet3',
+                                                  },
+                     }
+
+             }
+}
diff --git a/src/test/run_ipam_tests.pl b/src/test/run_ipam_tests.pl
new file mode 100755
index 0000000..ab8c7ac
--- /dev/null
+++ b/src/test/run_ipam_tests.pl
@@ -0,0 +1,126 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use lib qw(..);
+use File::Slurp;
+use NetAddr::IP qw(:lower);
+
+use Test::More;
+use Test::MockModule;
+
+use PVE::Network::SDN;
+use PVE::Network::SDN::Zones;
+use PVE::INotify;
+use PVE::LXC;
+use JSON;
+
+use Data::Dumper qw(Dumper);
+$Data::Dumper::Sortkeys = 1;
+
+sub read_sdn_config {
+    my ($file) = @_;
+    # Read structure back in again
+    open my $in, '<', $file or die $!;
+    my $sdn_config;
+    {
+	local $/;    # slurp mode
+	$sdn_config = eval <$in>;
+    }
+    close $in;
+    return $sdn_config;
+}
+
+
+my @plugins = read_dir( './ipams/', prefix => 1 ) ;
+
+foreach my $path (@plugins) {
+
+    my (undef, $testid) = split(/\//, $path);
+
+    print "test: $testid\n";
+    my $sdn_config = read_sdn_config ("$path/sdn_config");
+    my $pve_sdn_zones;
+    $pve_sdn_zones = Test::MockModule->new('PVE::Network::SDN::Zones');
+    $pve_sdn_zones->mock(
+	config => sub {
+	    return $sdn_config->{zones};
+	},
+    );
+
+    my $pve_sdn_vnets;
+    $pve_sdn_vnets = Test::MockModule->new('PVE::Network::SDN::Vnets');
+    $pve_sdn_vnets->mock(
+	config => sub {
+	    return $sdn_config->{vnets};
+	},
+    );
+
+    my $pve_sdn_subnets;
+    $pve_sdn_subnets = Test::MockModule->new('PVE::Network::SDN::Subnets');
+    $pve_sdn_subnets->mock(
+	config => sub {
+	    return $sdn_config->{subnets};
+	},
+	verify_dns_zone => sub {
+	    return;
+	},
+	add_dns_record => sub {
+	    return;
+	}
+    );
+
+    my $js = JSON->new;
+    $js->canonical(1);
+  
+    my $hostname = "myhostname";
+    my $mac = "da:65:8f:18:9b:6f";
+    my $description = "mydescription";
+    my $ipamdb = read_sdn_config ("$path/ipam.db");
+
+    my $plugin;
+    my $sdn_ipam_plugin;
+    $plugin = PVE::Network::SDN::Ipams::Plugin->lookup('pve');
+    $sdn_ipam_plugin = Test::MockModule->new($plugin);
+    $sdn_ipam_plugin->mock(
+        read_db => sub {
+	    return $ipamdb;
+	},
+	write_db => sub {
+	    my ($cfg) = @_;
+	    $ipamdb = $cfg;
+	}
+    );
+
+    my $pve_sdn_ipams;
+    $pve_sdn_ipams = Test::MockModule->new('PVE::Network::SDN::Ipams');
+    $pve_sdn_ipams->mock(
+	config => sub {
+	    my $ipam_config = read_sdn_config ("$path/ipam_config");
+	    return $ipam_config;
+	},
+    );
+
+
+    ## add_ip
+    my $test = "update_net";
+    my $name = "$testid $test";
+    my $oldnet = read_sdn_config("$path/oldnet");
+    my $net = read_sdn_config("$path/net");
+    my $expected_net = read_sdn_config("$path/net.expected");
+    my $expected_ipamdb = read_sdn_config("$path/ipam.db.expected");
+
+    eval {
+        PVE::LXC::update_net_ip($net, $oldnet, $hostname, $hostname, "description");
+    };
+    is(Dumper($net), Dumper($expected_net), "verify net");
+    is(Dumper($ipamdb), Dumper($expected_ipamdb), "verify ipam.db");
+
+
+
+}
+
+done_testing();
+
+
diff --git a/src/test/snapshot-input/sdn/subnets.cfg b/src/test/snapshot-input/sdn/subnets.cfg
new file mode 100644
index 0000000..e69de29
diff --git a/src/test/snapshot-test.pm b/src/test/snapshot-test.pm
index 91a2af9..73a0532 100644
--- a/src/test/snapshot-test.pm
+++ b/src/test/snapshot-test.pm
@@ -281,7 +281,6 @@ sub mocked_write_config {
 
 # END mocked PVE::LXC methods
 
-
 PVE::Tools::run_command("rm -rf snapshot-working");
 PVE::Tools::run_command("cp -a snapshot-input snapshot-working");
 
-- 
2.20.1




More information about the pve-devel mailing list