]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Rename Router related methods for VMware NSX plugin
authorarmando-migliaccio <armamig@gmail.com>
Thu, 16 Jan 2014 01:18:54 +0000 (17:18 -0800)
committerarmando-migliaccio <armamig@gmail.com>
Fri, 21 Feb 2014 22:15:52 +0000 (14:15 -0800)
This is another step for the renaming/refactoring of
nvplib and related modules. This is about routers.

Partial-implements blueprint: nicira-plugin-renaming

Change-Id: Ic69b2777fa1ae3125b8adf23943360e3fe18e4c2

13 files changed:
neutron/plugins/nicira/NeutronPlugin.py
neutron/plugins/nicira/NeutronServicePlugin.py
neutron/plugins/nicira/common/nsx_utils.py
neutron/plugins/nicira/common/sync.py
neutron/plugins/nicira/nsxlib/__init__.py
neutron/plugins/nicira/nsxlib/router.py [new file with mode: 0644]
neutron/plugins/nicira/nsxlib/versioning.py [new file with mode: 0644]
neutron/plugins/nicira/nvplib.py
neutron/tests/unit/nicira/nsxlib/test_router.py [new file with mode: 0644]
neutron/tests/unit/nicira/nsxlib/test_versioning.py [new file with mode: 0644]
neutron/tests/unit/nicira/test_nicira_plugin.py
neutron/tests/unit/nicira/test_nsx_utils.py
neutron/tests/unit/nicira/test_nvplib.py

index c4ad96bea42eef81bb0d1bd23604b480ee31f533..df1674595232f4555bdacfc616b77fd21a65934f 100644 (file)
@@ -77,6 +77,7 @@ from neutron.plugins.nicira.extensions import maclearning as mac_ext
 from neutron.plugins.nicira.extensions import nvp_networkgw as networkgw
 from neutron.plugins.nicira.extensions import nvp_qos as ext_qos
 from neutron.plugins.nicira.nsxlib import queue as queuelib
+from neutron.plugins.nicira.nsxlib import router as routerlib
 from neutron.plugins.nicira import NvpApiClient
 from neutron.plugins.nicira import nvplib
 
@@ -257,7 +258,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
                                                     port_data['fixed_ips'],
                                                     subnet_ids))
         try:
-            lrouter_port = nvplib.create_router_lport(
+            lrouter_port = routerlib.create_router_lport(
                 cluster, nsx_router_id, port_data.get('tenant_id', 'fake'),
                 port_data.get('id', 'fake'), port_data.get('name', 'fake'),
                 port_data.get('admin_state_up', True), ip_addresses,
@@ -314,7 +315,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
             # Be safe and concede NAT rules might not exist.
             # Therefore use min_num_expected=0
             for cidr in cidrs:
-                nvplib.delete_nat_rules_by_match(
+                routerlib.delete_nat_rules_by_match(
                     self.cluster, nsx_router_id, "SourceNatRule",
                     max_num_expected=1, min_num_expected=0,
                     source_ip_addresses=cidr)
@@ -324,7 +325,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
             # Set the SNAT rule for each subnet (only first IP)
             for cidr in cidrs:
                 cidr_prefix = int(cidr.split('/')[1])
-                nvplib.create_lrouter_snat_rule(
+                routerlib.create_lrouter_snat_rule(
                     self.cluster, nsx_router_id,
                     ip_addresses[0].split('/')[0],
                     ip_addresses[0].split('/')[0],
@@ -333,34 +334,34 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
 
     def _update_router_port_attachment(self, cluster, context,
                                        nsx_router_id, port_data,
-                                       nvp_router_port_id,
+                                       nsx_router_port_id,
                                        attachment_type,
                                        attachment,
                                        attachment_vlan=None):
-        if not nvp_router_port_id:
-            nvp_router_port_id = self._find_router_gw_port(context, port_data)
+        if not nsx_router_port_id:
+            nsx_router_port_id = self._find_router_gw_port(context, port_data)
         try:
-            nvplib.plug_router_port_attachment(cluster, nsx_router_id,
-                                               nvp_router_port_id,
-                                               attachment,
-                                               attachment_type,
-                                               attachment_vlan)
+            routerlib.plug_router_port_attachment(cluster, nsx_router_id,
+                                                  nsx_router_port_id,
+                                                  attachment,
+                                                  attachment_type,
+                                                  attachment_vlan)
             LOG.debug(_("Attached %(att)s to NVP router port %(port)s"),
-                      {'att': attachment, 'port': nvp_router_port_id})
+                      {'att': attachment, 'port': nsx_router_port_id})
         except NvpApiClient.NvpApiException:
             # Must remove NVP logical port
-            nvplib.delete_router_lport(cluster, nsx_router_id,
-                                       nvp_router_port_id)
+            routerlib.delete_router_lport(cluster, nsx_router_id,
+                                          nsx_router_port_id)
             LOG.exception(_("Unable to plug attachment in NVP logical "
                             "router port %(r_port_id)s, associated with "
                             "Neutron %(q_port_id)s"),
-                          {'r_port_id': nvp_router_port_id,
+                          {'r_port_id': nsx_router_port_id,
                            'q_port_id': port_data.get('id')})
             raise nvp_exc.NvpPluginException(
                 err_msg=(_("Unable to plug attachment in router port "
                            "%(r_port_id)s for neutron port id %(q_port_id)s "
                            "on router %(router_id)s") %
-                         {'r_port_id': nvp_router_port_id,
+                         {'r_port_id': nsx_router_port_id,
                           'q_port_id': port_data.get('id'),
                           'router_id': nsx_router_id}))
 
@@ -525,9 +526,9 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
         # Delete logical router port
         nsx_router_id = nsx_utils.get_nsx_router_id(
             context.session, self.cluster, port_data['device_id'])
-        nvp_switch_id, nvp_port_id = nsx_utils.get_nsx_switch_and_port_id(
+        nsx_switch_id, nsx_port_id = nsx_utils.get_nsx_switch_and_port_id(
             context.session, self.cluster, port_data['id'])
-        if not nvp_port_id:
+        if not nsx_port_id:
             LOG.warn(_("Neutron port %(port_id)s not found on NVP backend. "
                        "Terminating delete operation. A dangling router port "
                        "might have been left on router %(router_id)s"),
@@ -535,17 +536,17 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
                       'router_id': nsx_router_id})
             return
         try:
-            nvplib.delete_peer_router_lport(self.cluster,
-                                            nsx_router_id,
-                                            nvp_switch_id,
-                                            nvp_port_id)
+            routerlib.delete_peer_router_lport(self.cluster,
+                                               nsx_router_id,
+                                               nsx_switch_id,
+                                               nsx_port_id)
         except NvpApiClient.NvpApiException:
             # Do not raise because the issue might as well be that the
             # router has already been deleted, so there would be nothing
             # to do here
             LOG.exception(_("Ignoring exception as this means the peer "
                             "for port '%s' has already been deleted."),
-                          nvp_port_id)
+                          nsx_port_id)
 
         # Delete logical switch port
         self._nvp_delete_port(context, port_data)
@@ -599,8 +600,8 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
                                    port_data['network_id'])
         nsx_router_id = nsx_utils.get_nsx_router_id(
             context.session, self.cluster, router_id)
-        lr_port = nvplib.find_router_gw_port(context, self.cluster,
-                                             nsx_router_id)
+        lr_port = routerlib.find_router_gw_port(context, self.cluster,
+                                                nsx_router_id)
         if not lr_port:
             raise nvp_exc.NvpPluginException(
                 err_msg=(_("The gateway port for the NSX router %s "
@@ -624,14 +625,14 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
         # regardless of what the user specifies in neutron
         nsx_router_id = nsx_utils.get_nsx_router_id(
             context.session, self.cluster, port_data['device_id'])
-        nvplib.update_router_lport(self.cluster,
-                                   nsx_router_id,
-                                   lr_port['uuid'],
-                                   port_data['tenant_id'],
-                                   port_data['id'],
-                                   port_data['name'],
-                                   True,
-                                   ip_addresses)
+        routerlib.update_router_lport(self.cluster,
+                                      nsx_router_id,
+                                      lr_port['uuid'],
+                                      port_data['tenant_id'],
+                                      port_data['id'],
+                                      port_data['name'],
+                                      True,
+                                      ip_addresses)
         ext_network = self.get_network(context, port_data['network_id'])
         if ext_network.get(pnet.NETWORK_TYPE) == NetworkTypes.L3_EXT:
             # Update attachment
@@ -662,14 +663,14 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
             router_id = port_data['device_id']
             nsx_router_id = nsx_utils.get_nsx_router_id(
                 context.session, self.cluster, router_id)
-            nvplib.update_router_lport(self.cluster,
-                                       nsx_router_id,
-                                       lr_port['uuid'],
-                                       port_data['tenant_id'],
-                                       port_data['id'],
-                                       port_data['name'],
-                                       True,
-                                       ['0.0.0.0/31'])
+            routerlib.update_router_lport(self.cluster,
+                                          nsx_router_id,
+                                          lr_port['uuid'],
+                                          port_data['tenant_id'],
+                                          port_data['id'],
+                                          port_data['name'],
+                                          True,
+                                          ['0.0.0.0/31'])
             # Reset attachment
             self._update_router_port_attachment(
                 self.cluster, context, nsx_router_id, port_data,
@@ -1036,7 +1037,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
                        'device_owner': ['network:router_interface']}
         router_iface_ports = self.get_ports(context, filters=port_filter)
         for port in router_iface_ports:
-            nvp_switch_id, nvp_port_id = nsx_utils.get_nsx_switch_and_port_id(
+            nsx_switch_id, nsx_port_id = nsx_utils.get_nsx_switch_and_port_id(
                 context.session, self.cluster, id)
         # Before removing entry from Neutron DB, retrieve NSX switch
         # identifiers for removing them from backend
@@ -1047,13 +1048,13 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
         # clean up network owned ports
         for port in router_iface_ports:
             try:
-                if nvp_port_id:
+                if nsx_port_id:
                     nsx_router_id = nsx_utils.get_nsx_router_id(
                         context.session, self.cluster, port['device_id'])
-                    nvplib.delete_peer_router_lport(self.cluster,
-                                                    nsx_router_id,
-                                                    nvp_switch_id,
-                                                    nvp_port_id)
+                    routerlib.delete_peer_router_lport(self.cluster,
+                                                       nsx_router_id,
+                                                       nsx_switch_id,
+                                                       nsx_port_id)
                 else:
                     LOG.warning(_("A nvp lport identifier was not found for "
                                   "neutron port '%s'. Unable to remove "
@@ -1068,7 +1069,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
                 # to do here
                 LOG.warning(_("Ignoring exception as this means the peer for "
                               "port '%s' has already been deleted."),
-                            nvp_port_id)
+                            nsx_port_id)
 
         # Do not go to NVP for external networks
         if not external:
@@ -1395,7 +1396,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
         tenant_id = self._get_tenant_id_for_create(context, router)
         distributed = router.get('distributed')
         try:
-            lrouter = nvplib.create_lrouter(
+            lrouter = routerlib.create_lrouter(
                 self.cluster, router['id'],
                 tenant_id, router['name'], nexthop,
                 distributed=attr.is_attr_set(distributed) and distributed)
@@ -1424,7 +1425,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
                            'def_l3_gw_svc':
                            self.cluster.default_l3_gw_service_uuid})
             # Try and remove logical router from NVP
-            nvplib.delete_lrouter(self.cluster, lrouter['uuid'])
+            routerlib.delete_lrouter(self.cluster, lrouter['uuid'])
             # Return user a 500 with an apter message
             raise nvp_exc.NvpPluginException(
                 err_msg=(_("Unable to create router %s on NSX backend") %
@@ -1517,14 +1518,14 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
     def _update_lrouter(self, context, router_id, name, nexthop, routes=None):
         nsx_router_id = nsx_utils.get_nsx_router_id(
             context.session, self.cluster, router_id)
-        return nvplib.update_lrouter(
+        return routerlib.update_lrouter(
             self.cluster, nsx_router_id, name,
             nexthop, routes=routes)
 
     def _update_lrouter_routes(self, context, router_id, routes):
         nsx_router_id = nsx_utils.get_nsx_router_id(
             context.session, self.cluster, router_id)
-        nvplib.update_explicit_routes_lrouter(
+        routerlib.update_explicit_routes_lrouter(
             self.cluster, nsx_router_id, routes)
 
     def update_router(self, context, router_id, router):
@@ -1591,7 +1592,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
     def _delete_lrouter(self, context, router_id, nsx_router_id):
         # The neutron router id (router_id) is ignored in this routine,
         # but used in plugins deriving from this one
-        nvplib.delete_lrouter(self.cluster, nsx_router_id)
+        routerlib.delete_lrouter(self.cluster, nsx_router_id)
 
     def delete_router(self, context, router_id):
         with context.session.begin(subtransactions=True):
@@ -1660,7 +1661,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
                 cidr_prefix = int(subnet['cidr'].split('/')[1])
                 nsx_router_id = nsx_utils.get_nsx_router_id(
                     context.session, self.cluster, router['id'])
-                nvplib.create_lrouter_snat_rule(
+                routerlib.create_lrouter_snat_rule(
                     self.cluster, nsx_router_id, snat_ip, snat_ip,
                     order=NVP_EXTGW_NAT_RULES_ORDER - cidr_prefix,
                     match_criteria={'source_ip_addresses': subnet['cidr']})
@@ -1670,7 +1671,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
         if router.gw_port:
             nsx_router_id = nsx_utils.get_nsx_router_id(
                 context.session, self.cluster, router['id'])
-            nvplib.delete_nat_rules_by_match(
+            routerlib.delete_nat_rules_by_match(
                 self.cluster, nsx_router_id, "SourceNatRule",
                 max_num_expected=1, min_num_expected=1,
                 source_ip_addresses=subnet['cidr'])
@@ -1701,7 +1702,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
         # Fetch router from DB
         router = self._get_router(context, router_id)
         self._add_subnet_snat_rule(context, router, subnet)
-        nvplib.create_lrouter_nosnat_rule(
+        routerlib.create_lrouter_nosnat_rule(
             self.cluster, nsx_router_id,
             order=NVP_NOSNAT_RULES_ORDER,
             match_criteria={'destination_ip_addresses': subnet['cidr']})
@@ -1768,7 +1769,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
             # do not exist in 2.x deployments
             nsx_router_id = nsx_utils.get_nsx_router_id(
                 context.session, self.cluster, router_id)
-            nvplib.delete_nat_rules_by_match(
+            routerlib.delete_nat_rules_by_match(
                 self.cluster, nsx_router_id, "NoSourceNatRule",
                 max_num_expected=1, min_num_expected=0,
                 destination_ip_addresses=subnet['cidr'])
@@ -1790,19 +1791,19 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
         # but used by derived classes
         try:
             # Remove DNAT rule for the floating IP
-            nvplib.delete_nat_rules_by_match(
+            routerlib.delete_nat_rules_by_match(
                 self.cluster, nsx_router_id, "DestinationNatRule",
                 max_num_expected=1,
                 min_num_expected=min_num_rules_expected,
                 destination_ip_addresses=floating_ip_address)
 
             # Remove SNAT rules for the floating IP
-            nvplib.delete_nat_rules_by_match(
+            routerlib.delete_nat_rules_by_match(
                 self.cluster, nsx_router_id, "SourceNatRule",
                 max_num_expected=1,
                 min_num_expected=min_num_rules_expected,
                 source_ip_addresses=internal_ip)
-            nvplib.delete_nat_rules_by_match(
+            routerlib.delete_nat_rules_by_match(
                 self.cluster, nsx_router_id, "SourceNatRule",
                 max_num_expected=1,
                 min_num_expected=min_num_rules_expected,
@@ -1824,17 +1825,17 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
         router_id = fip_db.router_id
         nsx_router_id = nsx_utils.get_nsx_router_id(
             context.session, self.cluster, router_id)
-        nvp_gw_port_id = nvplib.find_router_gw_port(
+        nsx_gw_port_id = routerlib.find_router_gw_port(
             context, self.cluster, nsx_router_id)['uuid']
         ext_neutron_port_db = self._get_port(context.elevated(),
                                              fip_db.floating_port_id)
-        nvp_floating_ips = self._build_ip_address_list(
+        nsx_floating_ips = self._build_ip_address_list(
             context.elevated(), ext_neutron_port_db['fixed_ips'])
-        nvplib.update_lrouter_port_ips(self.cluster,
-                                       nsx_router_id,
-                                       nvp_gw_port_id,
-                                       ips_to_add=[],
-                                       ips_to_remove=nvp_floating_ips)
+        routerlib.update_lrouter_port_ips(self.cluster,
+                                          nsx_router_id,
+                                          nsx_gw_port_id,
+                                          ips_to_add=[],
+                                          ips_to_remove=nsx_floating_ips)
 
     def _get_fip_assoc_data(self, context, fip, floatingip_db):
         if (('fixed_ip_address' in fip and fip['fixed_ip_address']) and
@@ -1895,22 +1896,22 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
                           'port_id': floatingip_db.fixed_port_id,
                           'fixed_ip_address': floatingip_db.fixed_ip_address,
                           'tenant_id': floatingip_db.tenant_id})
-            nvp_gw_port_id = nvplib.find_router_gw_port(
+            nsx_gw_port_id = routerlib.find_router_gw_port(
                 context, self.cluster, nsx_old_router_id)['uuid']
             self._retrieve_and_delete_nat_rules(
                 context, floating_ip, old_internal_ip, nsx_old_router_id)
-            nvplib.update_lrouter_port_ips(
-                self.cluster, nsx_old_router_id, nvp_gw_port_id,
+            routerlib.update_lrouter_port_ips(
+                self.cluster, nsx_old_router_id, nsx_gw_port_id,
                 ips_to_add=[], ips_to_remove=nvp_floating_ips)
 
         if router_id:
-            nvp_gw_port_id = nvplib.find_router_gw_port(
+            nsx_gw_port_id = routerlib.find_router_gw_port(
                 context, self.cluster, nsx_router_id)['uuid']
             # Re-create NAT rules only if a port id is specified
             if fip.get('port_id'):
                 try:
                     # Setup DNAT rules for the floating IP
-                    nvplib.create_lrouter_dnat_rule(
+                    routerlib.create_lrouter_dnat_rule(
                         self.cluster, nsx_router_id, internal_ip,
                         order=NVP_FLOATINGIP_NAT_RULES_ORDER,
                         match_criteria={'destination_ip_addresses':
@@ -1928,7 +1929,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
                     internal_subnet_cidr = self._build_ip_address_list(
                         context, internal_port['fixed_ips'],
                         subnet_ids=subnet_ids)[0]
-                    nvplib.create_lrouter_snat_rule(
+                    routerlib.create_lrouter_snat_rule(
                         self.cluster, nsx_router_id, floating_ip, floating_ip,
                         order=NVP_NOSNAT_RULES_ORDER - 1,
                         match_criteria={'source_ip_addresses':
@@ -1937,17 +1938,15 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
                                         internal_ip})
                     # setup snat rule such that src ip of a IP packet when
                     # using floating is the floating ip itself.
-                    nvplib.create_lrouter_snat_rule(
+                    routerlib.create_lrouter_snat_rule(
                         self.cluster, nsx_router_id, floating_ip, floating_ip,
                         order=NVP_FLOATINGIP_NAT_RULES_ORDER,
                         match_criteria={'source_ip_addresses': internal_ip})
 
                     # Add Floating IP address to router_port
-                    nvplib.update_lrouter_port_ips(self.cluster,
-                                                   nsx_router_id,
-                                                   nvp_gw_port_id,
-                                                   ips_to_add=nvp_floating_ips,
-                                                   ips_to_remove=[])
+                    routerlib.update_lrouter_port_ips(
+                        self.cluster, nsx_router_id, nsx_gw_port_id,
+                        ips_to_add=nvp_floating_ips, ips_to_remove=[])
                 except NvpApiClient.NvpApiException:
                     LOG.exception(_("An error occurred while creating NAT "
                                     "rules on the NVP platform for floating "
index 348a381f09d3e5b3f421858128f643d887a74f5d..da0c7c2a92bc3d5957958698cd49463c33a0a379 100644 (file)
@@ -36,6 +36,7 @@ from neutron.plugins.nicira.dbexts import vcns_db
 from neutron.plugins.nicira.dbexts import vcns_models
 from neutron.plugins.nicira.extensions import servicerouter as sr
 from neutron.plugins.nicira import NeutronPlugin
+from neutron.plugins.nicira.nsxlib import router as routerlib
 from neutron.plugins.nicira import NvpApiClient
 from neutron.plugins.nicira import nvplib
 from neutron.plugins.nicira.vshield.common import (
@@ -425,7 +426,7 @@ class NvpAdvancedPlugin(sr_db.ServiceRouter_mixin,
             neutron_port_id = ''
             pname = name[:36] + '-lp'
             admin_status_enabled = True
-            lr_port = nvplib.create_router_lport(
+            lr_port = routerlib.create_router_lport(
                 self.cluster, lrouter['uuid'], tenant_id,
                 neutron_port_id, pname, admin_status_enabled,
                 [vcns_const.INTEGRATION_LR_IPADDRESS])
@@ -464,7 +465,7 @@ class NvpAdvancedPlugin(sr_db.ServiceRouter_mixin,
             msg = _("Unable to create integration logic switch "
                     "for router %s") % name
             LOG.exception(msg)
-            nvplib.delete_lrouter(self.cluster, lrouter['uuid'])
+            routerlib.delete_lrouter(self.cluster, lrouter['uuid'])
             raise q_exc.NeutronException(message=msg)
 
         try:
@@ -474,7 +475,7 @@ class NvpAdvancedPlugin(sr_db.ServiceRouter_mixin,
             msg = _("Unable to add router interface to integration lswitch "
                     "for router %s") % name
             LOG.exception(msg)
-            nvplib.delete_lrouter(self.cluster, lrouter['uuid'])
+            routerlib.delete_lrouter(self.cluster, lrouter['uuid'])
             raise q_exc.NeutronException(message=msg)
 
         try:
@@ -484,7 +485,7 @@ class NvpAdvancedPlugin(sr_db.ServiceRouter_mixin,
             msg = (_("Unable to create advance service router for %s") % name)
             LOG.exception(msg)
             self.vcns_driver.delete_lswitch(lswitch('uuid'))
-            nvplib.delete_lrouter(self.cluster, lrouter['uuid'])
+            routerlib.delete_lrouter(self.cluster, lrouter['uuid'])
             raise q_exc.NeutronException(message=msg)
 
         lrouter['status'] = service_constants.PENDING_CREATE
@@ -516,7 +517,7 @@ class NvpAdvancedPlugin(sr_db.ServiceRouter_mixin,
             self.vcns_driver.delete_edge(router_id, edge_id, jobdata=jobdata)
 
             # delete NSX logical router
-            nvplib.delete_lrouter(self.cluster, nsx_router_id)
+            routerlib.delete_lrouter(self.cluster, nsx_router_id)
 
         if id in self._router_type:
             del self._router_type[router_id]
@@ -563,7 +564,7 @@ class NvpAdvancedPlugin(sr_db.ServiceRouter_mixin,
 
     def _get_nvp_lrouter_status(self, id):
         try:
-            lrouter = nvplib.get_lrouter(self.cluster, id)
+            lrouter = routerlib.get_lrouter(self.cluster, id)
             lr_status = lrouter["_relations"]["LogicalRouterStatus"]
             if lr_status["fabric_status"]:
                 nvp_status = RouterStatus.ROUTER_STATUS_ACTIVE
@@ -587,9 +588,9 @@ class NvpAdvancedPlugin(sr_db.ServiceRouter_mixin,
 
     def _get_all_nvp_lrouters_statuses(self, tenant_id, fields):
         # get nvp lrouters status
-        nvp_lrouters = nvplib.get_lrouters(self.cluster,
-                                           tenant_id,
-                                           fields)
+        nvp_lrouters = routerlib.get_lrouters(self.cluster,
+                                              tenant_id,
+                                              fields)
 
         nvp_status = {}
         for nvp_lrouter in nvp_lrouters:
index 56b149854757944e30dcc79be39e61a9378803ed..208b2ea745fb92c531e81861fc5d6067a8efafb9 100644 (file)
@@ -18,6 +18,7 @@
 from neutron.openstack.common import log
 from neutron.plugins.nicira.dbexts import nicira_db
 from neutron.plugins.nicira import nsx_cluster
+from neutron.plugins.nicira.nsxlib import router as routerlib
 from neutron.plugins.nicira import NvpApiClient
 from neutron.plugins.nicira import nvplib
 
@@ -155,7 +156,7 @@ def get_nsx_router_id(session, cluster, neutron_router_id):
         # Find logical router from backend.
         # This is a rather expensive query, but it won't be executed
         # more than once for each router in Neutron's lifetime
-        nsx_routers = nvplib.query_lrouters(
+        nsx_routers = routerlib.query_lrouters(
             cluster, '*',
             filters={'tag': neutron_router_id,
                      'tag_scope': 'q_router_id'})
index 19543a781bc58389746123729e0c9f27b67ca416..dbbedf61cef6961bfb7023c99286ebbaccc67a63 100644 (file)
@@ -27,6 +27,7 @@ from neutron.openstack.common import loopingcall
 from neutron.openstack.common import timeutils
 from neutron.plugins.nicira.common import exceptions as nvp_exc
 from neutron.plugins.nicira.common import nsx_utils
+from neutron.plugins.nicira.nsxlib import router as routerlib
 from neutron.plugins.nicira import NvpApiClient
 from neutron.plugins.nicira import nvplib
 
@@ -191,7 +192,7 @@ class NvpSynchronizer():
         nvplib.LSWITCH_RESOURCE, fields='uuid,tags,fabric_status',
         relations='LogicalSwitchStatus')
     LR_URI = nvplib._build_uri_path(
-        nvplib.LROUTER_RESOURCE, fields='uuid,tags,fabric_status',
+        routerlib.LROUTER_RESOURCE, fields='uuid,tags,fabric_status',
         relations='LogicalRouterStatus')
     LP_URI = nvplib._build_uri_path(
         nvplib.LSWITCHPORT_RESOURCE,
@@ -319,7 +320,7 @@ class NvpSynchronizer():
                 # This query will return the logical router status too
                 nsx_router_id = nsx_utils.get_nsx_router_id(
                     context.session, self._cluster, neutron_router_data['id'])
-                lrouter = nvplib.get_lrouter(
+                lrouter = routerlib.get_lrouter(
                     self._cluster, nsx_router_id)
             except exceptions.NotFound:
                 # NOTE(salv-orlando): We should be catching
index c020e3bcdadf5fb9514fc11828270feebebb67f5..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
@@ -1,16 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2013 VMware, Inc.
-# All Rights Reserved
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
diff --git a/neutron/plugins/nicira/nsxlib/router.py b/neutron/plugins/nicira/nsxlib/router.py
new file mode 100644 (file)
index 0000000..b76b632
--- /dev/null
@@ -0,0 +1,676 @@
+# Copyright 2014 VMware, Inc.
+# All Rights Reserved
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from neutron.common import exceptions as exception
+from neutron.openstack.common import excutils
+from neutron.openstack.common import jsonutils
+from neutron.openstack.common import log
+from neutron.plugins.nicira.common import exceptions as nvp_exc
+from neutron.plugins.nicira.common import utils
+from neutron.plugins.nicira.nsxlib.versioning import DEFAULT_VERSION
+from neutron.plugins.nicira.nsxlib.versioning import versioned
+from neutron.plugins.nicira import NvpApiClient
+from neutron.plugins.nicira.nvplib import _build_uri_path
+from neutron.plugins.nicira.nvplib import do_request
+from neutron.plugins.nicira.nvplib import get_all_query_pages
+from neutron.plugins.nicira.nvplib import get_port
+
+HTTP_GET = "GET"
+HTTP_POST = "POST"
+HTTP_DELETE = "DELETE"
+HTTP_PUT = "PUT"
+
+LROUTER_RESOURCE = "lrouter"
+LROUTER_RESOURCE = "lrouter"
+LROUTERPORT_RESOURCE = "lport/%s" % LROUTER_RESOURCE
+LROUTERRIB_RESOURCE = "rib/%s" % LROUTER_RESOURCE
+LROUTERNAT_RESOURCE = "nat/lrouter"
+# Constants for NAT rules
+MATCH_KEYS = ["destination_ip_addresses", "destination_port_max",
+              "destination_port_min", "source_ip_addresses",
+              "source_port_max", "source_port_min", "protocol"]
+
+LOG = log.getLogger(__name__)
+
+
+def _prepare_lrouter_body(name, neutron_router_id, tenant_id,
+                          router_type, distributed=None, **kwargs):
+    body = {
+        "display_name": utils.check_and_truncate(name),
+        "tags": utils.get_tags(os_tid=tenant_id,
+                               q_router_id=neutron_router_id),
+        "routing_config": {
+            "type": router_type
+        },
+        "type": "LogicalRouterConfig"
+    }
+    # add the distributed key only if not None (ie: True or False)
+    if distributed is not None:
+        body['distributed'] = distributed
+    if kwargs:
+        body["routing_config"].update(kwargs)
+    return body
+
+
+def _create_implicit_routing_lrouter(cluster, neutron_router_id, tenant_id,
+                                     display_name, nexthop, distributed=None):
+    implicit_routing_config = {
+        "default_route_next_hop": {
+            "gateway_ip_address": nexthop,
+            "type": "RouterNextHop"
+        },
+    }
+    lrouter_obj = _prepare_lrouter_body(
+        display_name, neutron_router_id, tenant_id,
+        "SingleDefaultRouteImplicitRoutingConfig",
+        distributed=distributed,
+        **implicit_routing_config)
+    return do_request(HTTP_POST, _build_uri_path(LROUTER_RESOURCE),
+                      jsonutils.dumps(lrouter_obj), cluster=cluster)
+
+
+def create_implicit_routing_lrouter(cluster, neutron_router_id, tenant_id,
+                                    display_name, nexthop):
+    """Create a NSX logical router on the specified cluster.
+
+        :param cluster: The target NSX cluster
+        :param tenant_id: Identifier of the Openstack tenant for which
+        the logical router is being created
+        :param display_name: Descriptive name of this logical router
+        :param nexthop: External gateway IP address for the logical router
+        :raise NvpApiException: if there is a problem while communicating
+        with the NSX controller
+    """
+    return _create_implicit_routing_lrouter(
+        cluster, neutron_router_id, tenant_id, display_name, nexthop)
+
+
+def create_implicit_routing_lrouter_with_distribution(
+    cluster, neutron_router_id, tenant_id, display_name,
+    nexthop, distributed=None):
+    """Create a NSX logical router on the specified cluster.
+
+    This function also allows for creating distributed lrouters
+    :param cluster: The target NSX cluster
+    :param tenant_id: Identifier of the Openstack tenant for which
+    the logical router is being created
+    :param display_name: Descriptive name of this logical router
+    :param nexthop: External gateway IP address for the logical router
+    :param distributed: True for distributed logical routers
+    :raise NvpApiException: if there is a problem while communicating
+    with the NSX controller
+    """
+    return _create_implicit_routing_lrouter(
+        cluster, neutron_router_id, tenant_id,
+        display_name, nexthop, distributed)
+
+
+def create_explicit_routing_lrouter(cluster, neutron_router_id, tenant_id,
+                                    display_name, nexthop, distributed=None):
+    lrouter_obj = _prepare_lrouter_body(
+        display_name, neutron_router_id, tenant_id,
+        "RoutingTableRoutingConfig", distributed=distributed)
+    router = do_request(HTTP_POST, _build_uri_path(LROUTER_RESOURCE),
+                        jsonutils.dumps(lrouter_obj), cluster=cluster)
+    default_gw = {'prefix': '0.0.0.0/0', 'next_hop_ip': nexthop}
+    create_explicit_route_lrouter(cluster, router['uuid'], default_gw)
+    return router
+
+
+def delete_lrouter(cluster, lrouter_id):
+    do_request(HTTP_DELETE, _build_uri_path(LROUTER_RESOURCE,
+                                            resource_id=lrouter_id),
+               cluster=cluster)
+
+
+def get_lrouter(cluster, lrouter_id):
+    return do_request(HTTP_GET,
+                      _build_uri_path(LROUTER_RESOURCE,
+                                      resource_id=lrouter_id,
+                                      relations='LogicalRouterStatus'),
+                      cluster=cluster)
+
+
+def query_lrouters(cluster, fields=None, filters=None):
+    return get_all_query_pages(
+        _build_uri_path(LROUTER_RESOURCE,
+                        fields=fields,
+                        relations='LogicalRouterStatus',
+                        filters=filters),
+        cluster)
+
+
+def get_lrouters(cluster, tenant_id, fields=None, filters=None):
+    # FIXME(salv-orlando): Fields parameter is ignored in this routine
+    actual_filters = {}
+    if filters:
+        actual_filters.update(filters)
+    if tenant_id:
+        actual_filters['tag'] = tenant_id
+        actual_filters['tag_scope'] = 'os_tid'
+    lrouter_fields = "uuid,display_name,fabric_status,tags"
+    return query_lrouters(cluster, lrouter_fields, actual_filters)
+
+
+def update_implicit_routing_lrouter(cluster, r_id, display_name, nexthop):
+    lrouter_obj = get_lrouter(cluster, r_id)
+    if not display_name and not nexthop:
+        # Nothing to update
+        return lrouter_obj
+    # It seems that this is faster than the doing an if on display_name
+    lrouter_obj["display_name"] = (utils.check_and_truncate(display_name) or
+                                   lrouter_obj["display_name"])
+    if nexthop:
+        nh_element = lrouter_obj["routing_config"].get(
+            "default_route_next_hop")
+        if nh_element:
+            nh_element["gateway_ip_address"] = nexthop
+    return do_request(HTTP_PUT, _build_uri_path(LROUTER_RESOURCE,
+                                                resource_id=r_id),
+                      jsonutils.dumps(lrouter_obj),
+                      cluster=cluster)
+
+
+def get_explicit_routes_lrouter(cluster, router_id, protocol_type='static'):
+    static_filter = {'protocol': protocol_type}
+    existing_routes = do_request(
+        HTTP_GET,
+        _build_uri_path(LROUTERRIB_RESOURCE,
+                        filters=static_filter,
+                        fields="*",
+                        parent_resource_id=router_id),
+        cluster=cluster)['results']
+    return existing_routes
+
+
+def delete_explicit_route_lrouter(cluster, router_id, route_id):
+    do_request(HTTP_DELETE,
+               _build_uri_path(LROUTERRIB_RESOURCE,
+                               resource_id=route_id,
+                               parent_resource_id=router_id),
+               cluster=cluster)
+
+
+def create_explicit_route_lrouter(cluster, router_id, route):
+    next_hop_ip = route.get("nexthop") or route.get("next_hop_ip")
+    prefix = route.get("destination") or route.get("prefix")
+    uuid = do_request(
+        HTTP_POST,
+        _build_uri_path(LROUTERRIB_RESOURCE,
+                        parent_resource_id=router_id),
+        jsonutils.dumps({
+            "action": "accept",
+            "next_hop_ip": next_hop_ip,
+            "prefix": prefix,
+            "protocol": "static"
+        }),
+        cluster=cluster)['uuid']
+    return uuid
+
+
+def update_explicit_routes_lrouter(cluster, router_id, routes):
+    # Update in bulk: delete them all, and add the ones specified
+    # but keep track of what is been modified to allow roll-backs
+    # in case of failures
+    nsx_routes = get_explicit_routes_lrouter(cluster, router_id)
+    try:
+        deleted_routes = []
+        added_routes = []
+        # omit the default route (0.0.0.0/0) from the processing;
+        # this must be handled through the nexthop for the router
+        for route in nsx_routes:
+            prefix = route.get("destination") or route.get("prefix")
+            if prefix != '0.0.0.0/0':
+                delete_explicit_route_lrouter(cluster,
+                                              router_id,
+                                              route['uuid'])
+                deleted_routes.append(route)
+        for route in routes:
+            prefix = route.get("destination") or route.get("prefix")
+            if prefix != '0.0.0.0/0':
+                uuid = create_explicit_route_lrouter(cluster,
+                                                     router_id, route)
+                added_routes.append(uuid)
+    except NvpApiClient.NvpApiException:
+        LOG.exception(_('Cannot update NSX routes %(routes)s for '
+                        'router %(router_id)s'),
+                      {'routes': routes, 'router_id': router_id})
+        # Roll back to keep NSX in consistent state
+        with excutils.save_and_reraise_exception():
+            if nsx_routes:
+                if deleted_routes:
+                    for route in deleted_routes:
+                        create_explicit_route_lrouter(cluster,
+                                                      router_id, route)
+                if added_routes:
+                    for route_id in added_routes:
+                        delete_explicit_route_lrouter(cluster,
+                                                      router_id, route_id)
+    return nsx_routes
+
+
+def get_default_route_explicit_routing_lrouter_v33(cluster, router_id):
+    static_filter = {"protocol": "static",
+                     "prefix": "0.0.0.0/0"}
+    default_route = do_request(
+        HTTP_GET,
+        _build_uri_path(LROUTERRIB_RESOURCE,
+                        filters=static_filter,
+                        fields="*",
+                        parent_resource_id=router_id),
+        cluster=cluster)["results"][0]
+    return default_route
+
+
+def get_default_route_explicit_routing_lrouter_v32(cluster, router_id):
+    # Scan all routes because 3.2 does not support query by prefix
+    all_routes = get_explicit_routes_lrouter(cluster, router_id)
+    for route in all_routes:
+        if route['prefix'] == '0.0.0.0/0':
+            return route
+
+
+def update_default_gw_explicit_routing_lrouter(cluster, router_id, next_hop):
+    default_route = get_default_route_explicit_routing_lrouter(cluster,
+                                                               router_id)
+    if next_hop != default_route["next_hop_ip"]:
+        new_default_route = {"action": "accept",
+                             "next_hop_ip": next_hop,
+                             "prefix": "0.0.0.0/0",
+                             "protocol": "static"}
+        do_request(HTTP_PUT,
+                   _build_uri_path(LROUTERRIB_RESOURCE,
+                                   resource_id=default_route['uuid'],
+                                   parent_resource_id=router_id),
+                   jsonutils.dumps(new_default_route),
+                   cluster=cluster)
+
+
+def update_explicit_routing_lrouter(cluster, router_id,
+                                    display_name, next_hop, routes=None):
+    update_implicit_routing_lrouter(cluster, router_id, display_name, next_hop)
+    if next_hop:
+        update_default_gw_explicit_routing_lrouter(cluster,
+                                                   router_id, next_hop)
+    if routes is not None:
+        return update_explicit_routes_lrouter(cluster, router_id, routes)
+
+
+def query_lrouter_lports(cluster, lr_uuid, fields="*",
+                         filters=None, relations=None):
+    uri = _build_uri_path(LROUTERPORT_RESOURCE, parent_resource_id=lr_uuid,
+                          fields=fields, filters=filters, relations=relations)
+    return do_request(HTTP_GET, uri, cluster=cluster)['results']
+
+
+def create_router_lport(cluster, lrouter_uuid, tenant_id, neutron_port_id,
+                        display_name, admin_status_enabled, ip_addresses,
+                        mac_address=None):
+    """Creates a logical port on the assigned logical router."""
+    lport_obj = dict(
+        admin_status_enabled=admin_status_enabled,
+        display_name=display_name,
+        tags=utils.get_tags(os_tid=tenant_id, q_port_id=neutron_port_id),
+        ip_addresses=ip_addresses,
+        type="LogicalRouterPortConfig"
+    )
+    # Only add the mac_address to lport_obj if present. This is because
+    # when creating the fake_ext_gw there is no mac_address present.
+    if mac_address:
+        lport_obj['mac_address'] = mac_address
+    path = _build_uri_path(LROUTERPORT_RESOURCE,
+                           parent_resource_id=lrouter_uuid)
+    result = do_request(HTTP_POST, path, jsonutils.dumps(lport_obj),
+                        cluster=cluster)
+
+    LOG.debug(_("Created logical port %(lport_uuid)s on "
+                "logical router %(lrouter_uuid)s"),
+              {'lport_uuid': result['uuid'],
+               'lrouter_uuid': lrouter_uuid})
+    return result
+
+
+def update_router_lport(cluster, lrouter_uuid, lrouter_port_uuid,
+                        tenant_id, neutron_port_id, display_name,
+                        admin_status_enabled, ip_addresses):
+    """Updates a logical port on the assigned logical router."""
+    lport_obj = dict(
+        admin_status_enabled=admin_status_enabled,
+        display_name=display_name,
+        tags=utils.get_tags(os_tid=tenant_id, q_port_id=neutron_port_id),
+        ip_addresses=ip_addresses,
+        type="LogicalRouterPortConfig"
+    )
+    # Do not pass null items to NSX
+    for key in lport_obj.keys():
+        if lport_obj[key] is None:
+            del lport_obj[key]
+    path = _build_uri_path(LROUTERPORT_RESOURCE,
+                           lrouter_port_uuid,
+                           parent_resource_id=lrouter_uuid)
+    result = do_request(HTTP_PUT, path,
+                        jsonutils.dumps(lport_obj),
+                        cluster=cluster)
+    LOG.debug(_("Updated logical port %(lport_uuid)s on "
+                "logical router %(lrouter_uuid)s"),
+              {'lport_uuid': lrouter_port_uuid, 'lrouter_uuid': lrouter_uuid})
+    return result
+
+
+def delete_router_lport(cluster, lrouter_uuid, lport_uuid):
+    """Creates a logical port on the assigned logical router."""
+    path = _build_uri_path(LROUTERPORT_RESOURCE, lport_uuid, lrouter_uuid)
+    do_request(HTTP_DELETE, path, cluster=cluster)
+    LOG.debug(_("Delete logical router port %(lport_uuid)s on "
+                "logical router %(lrouter_uuid)s"),
+              {'lport_uuid': lport_uuid,
+               'lrouter_uuid': lrouter_uuid})
+
+
+def delete_peer_router_lport(cluster, lr_uuid, ls_uuid, lp_uuid):
+    nsx_port = get_port(cluster, ls_uuid, lp_uuid,
+                        relations="LogicalPortAttachment")
+    relations = nsx_port.get('_relations')
+    if relations:
+        att_data = relations.get('LogicalPortAttachment')
+        if att_data:
+            lrp_uuid = att_data.get('peer_port_uuid')
+            if lrp_uuid:
+                delete_router_lport(cluster, lr_uuid, lrp_uuid)
+
+
+def find_router_gw_port(context, cluster, router_id):
+    """Retrieves the external gateway port for a NSX logical router."""
+
+    # Find the uuid of nsx ext gw logical router port
+    # TODO(salvatore-orlando): Consider storing it in Neutron DB
+    results = query_lrouter_lports(
+        cluster, router_id,
+        relations="LogicalPortAttachment")
+    for lport in results:
+        if '_relations' in lport:
+            attachment = lport['_relations'].get('LogicalPortAttachment')
+            if attachment and attachment.get('type') == 'L3GatewayAttachment':
+                return lport
+
+
+def plug_router_port_attachment(cluster, router_id, port_id,
+                                attachment_uuid, nsx_attachment_type,
+                                attachment_vlan=None):
+    """Attach a router port to the given attachment.
+
+    Current attachment types:
+       - PatchAttachment [-> logical switch port uuid]
+       - L3GatewayAttachment [-> L3GatewayService uuid]
+    For the latter attachment type a VLAN ID can be specified as well.
+    """
+    uri = _build_uri_path(LROUTERPORT_RESOURCE, port_id, router_id,
+                          is_attachment=True)
+    attach_obj = {}
+    attach_obj["type"] = nsx_attachment_type
+    if nsx_attachment_type == "PatchAttachment":
+        attach_obj["peer_port_uuid"] = attachment_uuid
+    elif nsx_attachment_type == "L3GatewayAttachment":
+        attach_obj["l3_gateway_service_uuid"] = attachment_uuid
+        if attachment_vlan:
+            attach_obj['vlan_id'] = attachment_vlan
+    else:
+        raise nvp_exc.NvpInvalidAttachmentType(
+            attachment_type=nsx_attachment_type)
+    return do_request(
+        HTTP_PUT, uri, jsonutils.dumps(attach_obj), cluster=cluster)
+
+
+def _create_nat_match_obj(**kwargs):
+    nat_match_obj = {'ethertype': 'IPv4'}
+    delta = set(kwargs.keys()) - set(MATCH_KEYS)
+    if delta:
+        raise Exception(_("Invalid keys for NAT match: %s"), delta)
+    nat_match_obj.update(kwargs)
+    return nat_match_obj
+
+
+def _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj):
+    LOG.debug(_("Creating NAT rule: %s"), nat_rule_obj)
+    uri = _build_uri_path(LROUTERNAT_RESOURCE, parent_resource_id=router_id)
+    return do_request(HTTP_POST, uri, jsonutils.dumps(nat_rule_obj),
+                      cluster=cluster)
+
+
+def _build_snat_rule_obj(min_src_ip, max_src_ip, nat_match_obj):
+    return {"to_source_ip_address_min": min_src_ip,
+            "to_source_ip_address_max": max_src_ip,
+            "type": "SourceNatRule",
+            "match": nat_match_obj}
+
+
+def create_lrouter_nosnat_rule_v2(cluster, _router_id, _match_criteria=None):
+    LOG.info(_("No SNAT rules cannot be applied as they are not available in "
+               "this version of the NSX platform"))
+
+
+def create_lrouter_nodnat_rule_v2(cluster, _router_id, _match_criteria=None):
+    LOG.info(_("No DNAT rules cannot be applied as they are not available in "
+               "this version of the NSX platform"))
+
+
+def create_lrouter_snat_rule_v2(cluster, router_id,
+                                min_src_ip, max_src_ip, match_criteria=None):
+
+    nat_match_obj = _create_nat_match_obj(**match_criteria)
+    nat_rule_obj = _build_snat_rule_obj(min_src_ip, max_src_ip, nat_match_obj)
+    return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
+
+
+def create_lrouter_dnat_rule_v2(cluster, router_id, dst_ip,
+                                to_dst_port=None, match_criteria=None):
+
+    nat_match_obj = _create_nat_match_obj(**match_criteria)
+    nat_rule_obj = {
+        "to_destination_ip_address_min": dst_ip,
+        "to_destination_ip_address_max": dst_ip,
+        "type": "DestinationNatRule",
+        "match": nat_match_obj
+    }
+    if to_dst_port:
+        nat_rule_obj['to_destination_port'] = to_dst_port
+    return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
+
+
+def create_lrouter_nosnat_rule_v3(cluster, router_id, order=None,
+                                  match_criteria=None):
+    nat_match_obj = _create_nat_match_obj(**match_criteria)
+    nat_rule_obj = {
+        "type": "NoSourceNatRule",
+        "match": nat_match_obj
+    }
+    if order:
+        nat_rule_obj['order'] = order
+    return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
+
+
+def create_lrouter_nodnat_rule_v3(cluster, router_id, order=None,
+                                  match_criteria=None):
+    nat_match_obj = _create_nat_match_obj(**match_criteria)
+    nat_rule_obj = {
+        "type": "NoDestinationNatRule",
+        "match": nat_match_obj
+    }
+    if order:
+        nat_rule_obj['order'] = order
+    return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
+
+
+def create_lrouter_snat_rule_v3(cluster, router_id, min_src_ip, max_src_ip,
+                                order=None, match_criteria=None):
+    nat_match_obj = _create_nat_match_obj(**match_criteria)
+    nat_rule_obj = _build_snat_rule_obj(min_src_ip, max_src_ip, nat_match_obj)
+    if order:
+        nat_rule_obj['order'] = order
+    return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
+
+
+def create_lrouter_dnat_rule_v3(cluster, router_id, dst_ip, to_dst_port=None,
+                                order=None, match_criteria=None):
+
+    nat_match_obj = _create_nat_match_obj(**match_criteria)
+    nat_rule_obj = {
+        "to_destination_ip_address": dst_ip,
+        "type": "DestinationNatRule",
+        "match": nat_match_obj
+    }
+    if to_dst_port:
+        nat_rule_obj['to_destination_port'] = to_dst_port
+    if order:
+        nat_rule_obj['order'] = order
+    return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
+
+
+def delete_nat_rules_by_match(cluster, router_id, rule_type,
+                              max_num_expected,
+                              min_num_expected=0,
+                              **kwargs):
+    # remove nat rules
+    nat_rules = query_nat_rules(cluster, router_id)
+    to_delete_ids = []
+    for r in nat_rules:
+        if (r['type'] != rule_type):
+            continue
+
+        for key, value in kwargs.iteritems():
+            if not (key in r['match'] and r['match'][key] == value):
+                break
+        else:
+            to_delete_ids.append(r['uuid'])
+    if not (len(to_delete_ids) in
+            range(min_num_expected, max_num_expected + 1)):
+        raise nvp_exc.NvpNatRuleMismatch(actual_rules=len(to_delete_ids),
+                                         min_rules=min_num_expected,
+                                         max_rules=max_num_expected)
+
+    for rule_id in to_delete_ids:
+        delete_router_nat_rule(cluster, router_id, rule_id)
+
+
+def delete_router_nat_rule(cluster, router_id, rule_id):
+    uri = _build_uri_path(LROUTERNAT_RESOURCE, rule_id, router_id)
+    do_request(HTTP_DELETE, uri, cluster=cluster)
+
+
+def query_nat_rules(cluster, router_id, fields="*", filters=None):
+    uri = _build_uri_path(LROUTERNAT_RESOURCE, parent_resource_id=router_id,
+                          fields=fields, filters=filters)
+    return get_all_query_pages(uri, cluster)
+
+
+# NOTE(salvatore-orlando): The following FIXME applies in general to
+# each operation on list attributes.
+# FIXME(salvatore-orlando): need a lock around the list of IPs on an iface
+def update_lrouter_port_ips(cluster, lrouter_id, lport_id,
+                            ips_to_add, ips_to_remove):
+    uri = _build_uri_path(LROUTERPORT_RESOURCE, lport_id, lrouter_id)
+    try:
+        port = do_request(HTTP_GET, uri, cluster=cluster)
+        # TODO(salvatore-orlando): Enforce ips_to_add intersection with
+        # ips_to_remove is empty
+        ip_address_set = set(port['ip_addresses'])
+        ip_address_set = ip_address_set - set(ips_to_remove)
+        ip_address_set = ip_address_set | set(ips_to_add)
+        # Set is not JSON serializable - convert to list
+        port['ip_addresses'] = list(ip_address_set)
+        do_request(HTTP_PUT, uri, jsonutils.dumps(port), cluster=cluster)
+    except exception.NotFound as e:
+        # FIXME(salv-orlando):avoid raising different exception
+        data = {'lport_id': lport_id, 'lrouter_id': lrouter_id}
+        msg = (_("Router Port %(lport_id)s not found on router "
+                 "%(lrouter_id)s") % data)
+        LOG.exception(msg)
+        raise nvp_exc.NvpPluginException(err_msg=msg)
+    except NvpApiClient.NvpApiException as e:
+        msg = _("An exception occurred while updating IP addresses on a "
+                "router logical port:%s") % str(e)
+        LOG.exception(msg)
+        raise nvp_exc.NvpPluginException(err_msg=msg)
+
+
+ROUTER_FUNC_DICT = {
+    'create_lrouter': {
+        2: {DEFAULT_VERSION: create_implicit_routing_lrouter, },
+        3: {DEFAULT_VERSION: create_implicit_routing_lrouter,
+            1: create_implicit_routing_lrouter_with_distribution,
+            2: create_explicit_routing_lrouter, }, },
+    'update_lrouter': {
+        2: {DEFAULT_VERSION: update_implicit_routing_lrouter, },
+        3: {DEFAULT_VERSION: update_implicit_routing_lrouter,
+            2: update_explicit_routing_lrouter, }, },
+    'create_lrouter_dnat_rule': {
+        2: {DEFAULT_VERSION: create_lrouter_dnat_rule_v2, },
+        3: {DEFAULT_VERSION: create_lrouter_dnat_rule_v3, }, },
+    'create_lrouter_snat_rule': {
+        2: {DEFAULT_VERSION: create_lrouter_snat_rule_v2, },
+        3: {DEFAULT_VERSION: create_lrouter_snat_rule_v3, }, },
+    'create_lrouter_nosnat_rule': {
+        2: {DEFAULT_VERSION: create_lrouter_nosnat_rule_v2, },
+        3: {DEFAULT_VERSION: create_lrouter_nosnat_rule_v3, }, },
+    'create_lrouter_nodnat_rule': {
+        2: {DEFAULT_VERSION: create_lrouter_nodnat_rule_v2, },
+        3: {DEFAULT_VERSION: create_lrouter_nodnat_rule_v3, }, },
+    'get_default_route_explicit_routing_lrouter': {
+        3: {DEFAULT_VERSION: get_default_route_explicit_routing_lrouter_v32,
+            2: get_default_route_explicit_routing_lrouter_v32, }, },
+}
+
+
+@versioned(ROUTER_FUNC_DICT)
+def create_lrouter(cluster, *args, **kwargs):
+    if kwargs.get('distributed', None):
+        v = cluster.api_client.get_nvp_version()
+        if (v.major, v.minor) < (3, 1):
+            raise nvp_exc.NvpInvalidVersion(version=v)
+        return v
+
+
+@versioned(ROUTER_FUNC_DICT)
+def get_default_route_explicit_routing_lrouter(cluster, *args, **kwargs):
+    pass
+
+
+@versioned(ROUTER_FUNC_DICT)
+def update_lrouter(cluster, *args, **kwargs):
+    if kwargs.get('routes', None):
+        v = cluster.api_client.get_nvp_version()
+        if (v.major, v.minor) < (3, 2):
+            raise nvp_exc.NvpInvalidVersion(version=v)
+        return v
+
+
+@versioned(ROUTER_FUNC_DICT)
+def create_lrouter_dnat_rule(cluster, *args, **kwargs):
+    pass
+
+
+@versioned(ROUTER_FUNC_DICT)
+def create_lrouter_snat_rule(cluster, *args, **kwargs):
+    pass
+
+
+@versioned(ROUTER_FUNC_DICT)
+def create_lrouter_nosnat_rule(cluster, *args, **kwargs):
+    pass
+
+
+@versioned(ROUTER_FUNC_DICT)
+def create_lrouter_nodnat_rule(cluster, *args, **kwargs):
+    pass
diff --git a/neutron/plugins/nicira/nsxlib/versioning.py b/neutron/plugins/nicira/nsxlib/versioning.py
new file mode 100644 (file)
index 0000000..dfa4cb6
--- /dev/null
@@ -0,0 +1,66 @@
+# Copyright 2014 VMware, Inc.
+# All Rights Reserved
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import inspect
+
+from neutron.plugins.nicira import NvpApiClient
+
+DEFAULT_VERSION = -1
+
+
+def versioned(func_table):
+
+    def versioned_function(wrapped_func):
+        func_name = wrapped_func.__name__
+
+        def dispatch_versioned_function(cluster, *args, **kwargs):
+            # Call the wrapper function, in case we need to
+            # run validation checks regarding versions. It
+            # should return the NVP version
+            v = (wrapped_func(cluster, *args, **kwargs) or
+                 cluster.api_client.get_nvp_version())
+            func = get_function_by_version(func_table, func_name, v)
+            func_kwargs = kwargs
+            arg_spec = inspect.getargspec(func)
+            if not arg_spec.keywords and not arg_spec.varargs:
+                # drop args unknown to function from func_args
+                arg_set = set(func_kwargs.keys())
+                for arg in arg_set - set(arg_spec.args):
+                    del func_kwargs[arg]
+            # NOTE(salvatore-orlando): shall we fail here if a required
+            # argument is not passed, or let the called function raise?
+            return func(cluster, *args, **func_kwargs)
+
+        return dispatch_versioned_function
+    return versioned_function
+
+
+def get_function_by_version(func_table, func_name, ver):
+    if ver:
+        if ver.major not in func_table[func_name]:
+            major = max(func_table[func_name].keys())
+            minor = max(func_table[func_name][major].keys())
+            if major > ver.major:
+                raise NotImplementedError(_("Operation may not be supported"))
+        else:
+            major = ver.major
+            minor = ver.minor
+            if ver.minor not in func_table[func_name][major]:
+                minor = DEFAULT_VERSION
+        return func_table[func_name][major][minor]
+    else:
+        msg = _('NSX version is not set. Unable to complete request '
+                'correctly. Check log for NSX communication errors.')
+        raise NvpApiClient.ServiceUnavailable(message=msg)
index d151ebe8312a7fffe9854ff7a6473df636099d60..3c5987063e085e2684565c36ca9af6d748211d8d 100644 (file)
 
 
 import hashlib
-import inspect
 import json
 
 #FIXME(danwent): I'd like this file to get to the point where it has
 # no neutron-specific logic in it
 from neutron.common import constants
 from neutron.common import exceptions as exception
-from neutron.openstack.common import excutils
 from neutron.openstack.common import log
 from neutron.plugins.nicira.common import exceptions as nvp_exc
 from neutron.plugins.nicira.common import utils
@@ -47,23 +45,10 @@ URI_PREFIX = "/ws.v1"
 # Resources exposed by NVP API
 LSWITCH_RESOURCE = "lswitch"
 LSWITCHPORT_RESOURCE = "lport/%s" % LSWITCH_RESOURCE
-LROUTER_RESOURCE = "lrouter"
-LROUTERPORT_RESOURCE = "lport/%s" % LROUTER_RESOURCE
-LROUTERRIB_RESOURCE = "rib/%s" % LROUTER_RESOURCE
-LROUTERNAT_RESOURCE = "nat/lrouter"
-LQUEUE_RESOURCE = "lqueue"
 GWSERVICE_RESOURCE = "gateway-service"
 # Current neutron version
 NEUTRON_VERSION = version_info.release_string()
-# Constants for NAT rules
-MATCH_KEYS = ["destination_ip_addresses", "destination_port_max",
-              "destination_port_min", "source_ip_addresses",
-              "source_port_max", "source_port_min", "protocol"]
 
-SNAT_KEYS = ["to_src_port_min", "to_src_port_max", "to_src_ip_min",
-             "to_src_ip_max"]
-
-DNAT_KEYS = ["to_dst_port", "to_dst_ip_min", "to_dst_ip_max"]
 # Maximum page size for a single request
 # NOTE(salv-orlando): This might become a version-dependent map should the
 # limit be raised in future versions
@@ -91,30 +76,6 @@ def device_id_to_vm_id(device_id, obfuscate=False):
         return device_id
 
 
-def version_dependent(wrapped_func):
-    func_name = wrapped_func.__name__
-
-    def dispatch_version_dependent_function(cluster, *args, **kwargs):
-        # Call the wrapper function, in case we need to
-        # run validation checks regarding versions. It
-        # should return the NVP version
-        v = (wrapped_func(cluster, *args, **kwargs) or
-             cluster.api_client.get_nvp_version())
-        func = get_function_by_version(func_name, v)
-        func_kwargs = kwargs
-        arg_spec = inspect.getargspec(func)
-        if not arg_spec.keywords and not arg_spec.varargs:
-            # drop args unknown to function from func_args
-            arg_set = set(func_kwargs.keys())
-            for arg in arg_set - set(arg_spec.args):
-                del func_kwargs[arg]
-        # NOTE(salvatore-orlando): shall we fail here if a required
-        # argument is not passed, or let the called function raise?
-        return func(cluster, *args, **func_kwargs)
-
-    return dispatch_version_dependent_function
-
-
 def _build_uri_path(resource,
                     resource_id=None,
                     parent_resource_id=None,
@@ -317,122 +278,12 @@ def create_l2_gw_service(cluster, tenant_id, display_name, devices):
         json.dumps(gwservice_obj), cluster=cluster)
 
 
-def _prepare_lrouter_body(name, neutron_router_id, tenant_id, router_type,
-                          distributed=None, **kwargs):
-    body = {
-        "display_name": utils.check_and_truncate(name),
-        "tags": [{"tag": tenant_id, "scope": "os_tid"},
-                 {"tag": neutron_router_id, "scope": "q_router_id"},
-                 {"tag": NEUTRON_VERSION, "scope": "quantum"}],
-        "routing_config": {
-            "type": router_type
-        },
-        "type": "LogicalRouterConfig"
-    }
-    # add the distributed key only if not None (ie: True or False)
-    if distributed is not None:
-        body['distributed'] = distributed
-    if kwargs:
-        body["routing_config"].update(kwargs)
-    return body
-
-
-def _create_implicit_routing_lrouter(cluster, neutron_router_id, tenant_id,
-                                     display_name, nexthop, distributed=None):
-    implicit_routing_config = {
-        "default_route_next_hop": {
-            "gateway_ip_address": nexthop,
-            "type": "RouterNextHop"
-        },
-    }
-    lrouter_obj = _prepare_lrouter_body(
-        display_name, neutron_router_id, tenant_id,
-        "SingleDefaultRouteImplicitRoutingConfig",
-        distributed=distributed,
-        **implicit_routing_config)
-    return do_request(HTTP_POST, _build_uri_path(LROUTER_RESOURCE),
-                      json.dumps(lrouter_obj), cluster=cluster)
-
-
-def create_implicit_routing_lrouter(cluster, neutron_router_id, tenant_id,
-                                    display_name, nexthop):
-    """Create a NVP logical router on the specified cluster.
-
-        :param cluster: The target NVP cluster
-        :param tenant_id: Identifier of the Openstack tenant for which
-        the logical router is being created
-        :param display_name: Descriptive name of this logical router
-        :param nexthop: External gateway IP address for the logical router
-        :raise NvpApiException: if there is a problem while communicating
-        with the NVP controller
-    """
-    return _create_implicit_routing_lrouter(
-        cluster, neutron_router_id, tenant_id, display_name, nexthop)
-
-
-def create_implicit_routing_lrouter_with_distribution(
-    cluster, neutron_router_id, tenant_id,
-    display_name, nexthop, distributed=None):
-    """Create a NVP logical router on the specified cluster.
-
-    This function also allows for creating distributed lrouters
-    :param cluster: The target NVP cluster
-    :param tenant_id: Identifier of the Openstack tenant for which
-    the logical router is being created
-    :param display_name: Descriptive name of this logical router
-    :param nexthop: External gateway IP address for the logical router
-    :param distributed: True for distributed logical routers
-    :raise NvpApiException: if there is a problem while communicating
-    with the NVP controller
-    """
-    return _create_implicit_routing_lrouter(
-        cluster, neutron_router_id, tenant_id,
-        display_name, nexthop, distributed)
-
-
-def create_explicit_routing_lrouter(cluster, neutron_router_id, tenant_id,
-                                    display_name, nexthop,
-                                    distributed=None):
-    lrouter_obj = _prepare_lrouter_body(
-        display_name, neutron_router_id,
-        tenant_id, "RoutingTableRoutingConfig",
-        distributed=distributed)
-    router = do_request(HTTP_POST, _build_uri_path(LROUTER_RESOURCE),
-                        json.dumps(lrouter_obj), cluster=cluster)
-    default_gw = {'prefix': '0.0.0.0/0', 'next_hop_ip': nexthop}
-    create_explicit_route_lrouter(cluster, router['uuid'], default_gw)
-    return router
-
-
-@version_dependent
-def create_lrouter(cluster, *args, **kwargs):
-    if kwargs.get('distributed', None):
-        v = cluster.api_client.get_nvp_version()
-        if (v.major, v.minor) < (3, 1):
-            raise nvp_exc.NvpInvalidVersion(version=v)
-        return v
-
-
-def delete_lrouter(cluster, lrouter_id):
-    do_request(HTTP_DELETE, _build_uri_path(LROUTER_RESOURCE,
-                                            resource_id=lrouter_id),
-               cluster=cluster)
-
-
 def delete_l2_gw_service(cluster, gateway_id):
     do_request("DELETE", _build_uri_path(GWSERVICE_RESOURCE,
                                          resource_id=gateway_id),
                cluster=cluster)
 
 
-def get_lrouter(cluster, lrouter_id):
-    return do_request(HTTP_GET,
-                      _build_uri_path(LROUTER_RESOURCE,
-                                      resource_id=lrouter_id,
-                                      relations='LogicalRouterStatus'),
-                      cluster=cluster)
-
-
 def get_l2_gw_service(cluster, gateway_id):
     return do_request(
         "GET", _build_uri_path(GWSERVICE_RESOURCE,
@@ -440,27 +291,6 @@ def get_l2_gw_service(cluster, gateway_id):
         cluster=cluster)
 
 
-def query_lrouters(cluster, fields=None, filters=None):
-    return get_all_query_pages(
-        _build_uri_path(LROUTER_RESOURCE,
-                        fields=fields,
-                        relations='LogicalRouterStatus',
-                        filters=filters),
-        cluster)
-
-
-def get_lrouters(cluster, tenant_id, fields=None, filters=None):
-    # FIXME(salv-orlando): Fields parameter is ignored in this routine
-    actual_filters = {}
-    if filters:
-        actual_filters.update(filters)
-    if tenant_id:
-        actual_filters['tag'] = tenant_id
-        actual_filters['tag_scope'] = 'os_tid'
-    lrouter_fields = "uuid,display_name,fabric_status,tags"
-    return query_lrouters(cluster, lrouter_fields, actual_filters)
-
-
 def get_l2_gw_services(cluster, tenant_id=None,
                        fields=None, filters=None):
     actual_filters = dict(filters or {})
@@ -485,164 +315,6 @@ def update_l2_gw_service(cluster, gateway_id, display_name):
                       json.dumps(gwservice_obj), cluster=cluster)
 
 
-def update_implicit_routing_lrouter(cluster, r_id, display_name, nexthop):
-    lrouter_obj = get_lrouter(cluster, r_id)
-    if not display_name and not nexthop:
-        # Nothing to update
-        return lrouter_obj
-    # It seems that this is faster than the doing an if on display_name
-    lrouter_obj["display_name"] = (utils.check_and_truncate(display_name) or
-                                   lrouter_obj["display_name"])
-    if nexthop:
-        nh_element = lrouter_obj["routing_config"].get(
-            "default_route_next_hop")
-        if nh_element:
-            nh_element["gateway_ip_address"] = nexthop
-    return do_request(HTTP_PUT, _build_uri_path(LROUTER_RESOURCE,
-                                                resource_id=r_id),
-                      json.dumps(lrouter_obj),
-                      cluster=cluster)
-
-
-def get_explicit_routes_lrouter(cluster, router_id, protocol_type='static'):
-    static_filter = {'protocol': protocol_type}
-    existing_routes = do_request(
-        HTTP_GET,
-        _build_uri_path(LROUTERRIB_RESOURCE,
-                        filters=static_filter,
-                        fields="*",
-                        parent_resource_id=router_id),
-        cluster=cluster)['results']
-    return existing_routes
-
-
-def delete_explicit_route_lrouter(cluster, router_id, route_id):
-    do_request(HTTP_DELETE,
-               _build_uri_path(LROUTERRIB_RESOURCE,
-                               resource_id=route_id,
-                               parent_resource_id=router_id),
-               cluster=cluster)
-
-
-def create_explicit_route_lrouter(cluster, router_id, route):
-    next_hop_ip = route.get("nexthop") or route.get("next_hop_ip")
-    prefix = route.get("destination") or route.get("prefix")
-    uuid = do_request(
-        HTTP_POST,
-        _build_uri_path(LROUTERRIB_RESOURCE,
-                        parent_resource_id=router_id),
-        json.dumps({
-            "action": "accept",
-            "next_hop_ip": next_hop_ip,
-            "prefix": prefix,
-            "protocol": "static"
-        }),
-        cluster=cluster)['uuid']
-    return uuid
-
-
-def update_explicit_routes_lrouter(cluster, router_id, routes):
-    # Update in bulk: delete them all, and add the ones specified
-    # but keep track of what is been modified to allow roll-backs
-    # in case of failures
-    nvp_routes = get_explicit_routes_lrouter(cluster, router_id)
-    try:
-        deleted_routes = []
-        added_routes = []
-        # omit the default route (0.0.0.0/0) from the processing;
-        # this must be handled through the nexthop for the router
-        for route in nvp_routes:
-            prefix = route.get("destination") or route.get("prefix")
-            if prefix != '0.0.0.0/0':
-                delete_explicit_route_lrouter(cluster,
-                                              router_id,
-                                              route['uuid'])
-                deleted_routes.append(route)
-        for route in routes:
-            prefix = route.get("destination") or route.get("prefix")
-            if prefix != '0.0.0.0/0':
-                uuid = create_explicit_route_lrouter(cluster,
-                                                     router_id, route)
-                added_routes.append(uuid)
-    except NvpApiClient.NvpApiException:
-        LOG.exception(_('Cannot update NVP routes %(routes)s for '
-                        'router %(router_id)s'),
-                      {'routes': routes, 'router_id': router_id})
-        # Roll back to keep NVP in consistent state
-        with excutils.save_and_reraise_exception():
-            if nvp_routes:
-                if deleted_routes:
-                    for route in deleted_routes:
-                        create_explicit_route_lrouter(cluster,
-                                                      router_id, route)
-                if added_routes:
-                    for route_id in added_routes:
-                        delete_explicit_route_lrouter(cluster,
-                                                      router_id, route_id)
-    return nvp_routes
-
-
-@version_dependent
-def get_default_route_explicit_routing_lrouter(cluster, *args, **kwargs):
-    pass
-
-
-def get_default_route_explicit_routing_lrouter_v33(cluster, router_id):
-    static_filter = {"protocol": "static",
-                     "prefix": "0.0.0.0/0"}
-    default_route = do_request(
-        HTTP_GET,
-        _build_uri_path(LROUTERRIB_RESOURCE,
-                        filters=static_filter,
-                        fields="*",
-                        parent_resource_id=router_id),
-        cluster=cluster)["results"][0]
-    return default_route
-
-
-def get_default_route_explicit_routing_lrouter_v32(cluster, router_id):
-    # Scan all routes because 3.2 does not support query by prefix
-    all_routes = get_explicit_routes_lrouter(cluster, router_id)
-    for route in all_routes:
-        if route['prefix'] == '0.0.0.0/0':
-            return route
-
-
-def update_default_gw_explicit_routing_lrouter(cluster, router_id, next_hop):
-    default_route = get_default_route_explicit_routing_lrouter(cluster,
-                                                               router_id)
-    if next_hop != default_route["next_hop_ip"]:
-        new_default_route = {"action": "accept",
-                             "next_hop_ip": next_hop,
-                             "prefix": "0.0.0.0/0",
-                             "protocol": "static"}
-        do_request(HTTP_PUT,
-                   _build_uri_path(LROUTERRIB_RESOURCE,
-                                   resource_id=default_route['uuid'],
-                                   parent_resource_id=router_id),
-                   json.dumps(new_default_route),
-                   cluster=cluster)
-
-
-def update_explicit_routing_lrouter(cluster, router_id,
-                                    display_name, next_hop, routes=None):
-    update_implicit_routing_lrouter(cluster, router_id, display_name, next_hop)
-    if next_hop:
-        update_default_gw_explicit_routing_lrouter(cluster,
-                                                   router_id, next_hop)
-    if routes is not None:
-        return update_explicit_routes_lrouter(cluster, router_id, routes)
-
-
-@version_dependent
-def update_lrouter(cluster, *args, **kwargs):
-    if kwargs.get('routes', None):
-        v = cluster.api_client.get_nvp_version()
-        if (v.major, v.minor) < (3, 2):
-            raise nvp_exc.NvpInvalidVersion(version=v)
-        return v
-
-
 def delete_network(cluster, net_id, lswitch_id):
     delete_networks(cluster, net_id, [lswitch_id])
 
@@ -669,13 +341,6 @@ def query_lswitch_lports(cluster, ls_uuid, fields="*",
     return do_request(HTTP_GET, uri, cluster=cluster)['results']
 
 
-def query_lrouter_lports(cluster, lr_uuid, fields="*",
-                         filters=None, relations=None):
-    uri = _build_uri_path(LROUTERPORT_RESOURCE, parent_resource_id=lr_uuid,
-                          fields=fields, filters=filters, relations=relations)
-    return do_request(HTTP_GET, uri, cluster=cluster)['results']
-
-
 def delete_port(cluster, switch, port):
     uri = "/ws.v1/lswitch/" + switch + "/lport/" + port
     try:
@@ -884,129 +549,6 @@ def create_lport(cluster, lswitch_uuid, tenant_id, neutron_port_id,
     return result
 
 
-def create_router_lport(cluster, lrouter_uuid, tenant_id, neutron_port_id,
-                        display_name, admin_status_enabled, ip_addresses,
-                        mac_address=None):
-    """Creates a logical port on the assigned logical router."""
-    tags = [dict(scope='os_tid', tag=tenant_id),
-            dict(scope='q_port_id', tag=neutron_port_id),
-            dict(scope='quantum', tag=NEUTRON_VERSION)]
-
-    lport_obj = dict(
-        admin_status_enabled=admin_status_enabled,
-        display_name=display_name,
-        tags=tags,
-        ip_addresses=ip_addresses,
-        type="LogicalRouterPortConfig"
-    )
-    # Only add the mac_address to lport_obj if present. This is because
-    # when creating the fake_ext_gw there is no mac_address present.
-    if mac_address:
-        lport_obj['mac_address'] = mac_address
-    path = _build_uri_path(LROUTERPORT_RESOURCE,
-                           parent_resource_id=lrouter_uuid)
-    result = do_request(HTTP_POST, path, json.dumps(lport_obj),
-                        cluster=cluster)
-
-    LOG.debug(_("Created logical port %(lport_uuid)s on "
-                "logical router %(lrouter_uuid)s"),
-              {'lport_uuid': result['uuid'],
-               'lrouter_uuid': lrouter_uuid})
-    return result
-
-
-def update_router_lport(cluster, lrouter_uuid, lrouter_port_uuid,
-                        tenant_id, neutron_port_id, display_name,
-                        admin_status_enabled, ip_addresses):
-    """Updates a logical port on the assigned logical router."""
-    lport_obj = dict(
-        admin_status_enabled=admin_status_enabled,
-        display_name=display_name,
-        tags=[dict(scope='os_tid', tag=tenant_id),
-              dict(scope='q_port_id', tag=neutron_port_id),
-              dict(scope='quantum', tag=NEUTRON_VERSION)],
-        ip_addresses=ip_addresses,
-        type="LogicalRouterPortConfig"
-    )
-    # Do not pass null items to NVP
-    for key in lport_obj.keys():
-        if lport_obj[key] is None:
-            del lport_obj[key]
-    path = _build_uri_path(LROUTERPORT_RESOURCE,
-                           lrouter_port_uuid,
-                           parent_resource_id=lrouter_uuid)
-    result = do_request(HTTP_PUT, path,
-                        json.dumps(lport_obj),
-                        cluster=cluster)
-    LOG.debug(_("Updated logical port %(lport_uuid)s on "
-                "logical router %(lrouter_uuid)s"),
-              {'lport_uuid': lrouter_port_uuid, 'lrouter_uuid': lrouter_uuid})
-    return result
-
-
-def delete_router_lport(cluster, lrouter_uuid, lport_uuid):
-    """Creates a logical port on the assigned logical router."""
-    path = _build_uri_path(LROUTERPORT_RESOURCE, lport_uuid, lrouter_uuid)
-    do_request(HTTP_DELETE, path, cluster=cluster)
-    LOG.debug(_("Delete logical router port %(lport_uuid)s on "
-                "logical router %(lrouter_uuid)s"),
-              {'lport_uuid': lport_uuid,
-               'lrouter_uuid': lrouter_uuid})
-
-
-def delete_peer_router_lport(cluster, lr_uuid, ls_uuid, lp_uuid):
-    nvp_port = get_port(cluster, ls_uuid, lp_uuid,
-                        relations="LogicalPortAttachment")
-    relations = nvp_port.get('_relations')
-    if relations:
-        att_data = relations.get('LogicalPortAttachment')
-        if att_data:
-            lrp_uuid = att_data.get('peer_port_uuid')
-            if lrp_uuid:
-                delete_router_lport(cluster, lr_uuid, lrp_uuid)
-
-
-def find_router_gw_port(context, cluster, router_id):
-    """Retrieves the external gateway port for a NVP logical router."""
-
-    # Find the uuid of nvp ext gw logical router port
-    # TODO(salvatore-orlando): Consider storing it in Neutron DB
-    results = query_lrouter_lports(
-        cluster, router_id,
-        relations="LogicalPortAttachment")
-    for lport in results:
-        if '_relations' in lport:
-            attachment = lport['_relations'].get('LogicalPortAttachment')
-            if attachment and attachment.get('type') == 'L3GatewayAttachment':
-                return lport
-
-
-def plug_router_port_attachment(cluster, router_id, port_id,
-                                attachment_uuid, nvp_attachment_type,
-                                attachment_vlan=None):
-    """Attach a router port to the given attachment.
-
-    Current attachment types:
-       - PatchAttachment [-> logical switch port uuid]
-       - L3GatewayAttachment [-> L3GatewayService uuid]
-    For the latter attachment type a VLAN ID can be specified as well.
-    """
-    uri = _build_uri_path(LROUTERPORT_RESOURCE, port_id, router_id,
-                          is_attachment=True)
-    attach_obj = {}
-    attach_obj["type"] = nvp_attachment_type
-    if nvp_attachment_type == "PatchAttachment":
-        attach_obj["peer_port_uuid"] = attachment_uuid
-    elif nvp_attachment_type == "L3GatewayAttachment":
-        attach_obj["l3_gateway_service_uuid"] = attachment_uuid
-        if attachment_vlan:
-            attach_obj['vlan_id'] = attachment_vlan
-    else:
-        raise nvp_exc.NvpInvalidAttachmentType(
-            attachment_type=nvp_attachment_type)
-    return do_request(HTTP_PUT, uri, json.dumps(attach_obj), cluster=cluster)
-
-
 def get_port_status(cluster, lswitch_id, port_id):
     """Retrieve the operational status of the port."""
     try:
@@ -1176,243 +718,3 @@ def delete_security_profile(cluster, spid):
         LOG.warn(_("Unable to find security profile %s on NSX backend"),
                  spid)
         raise
-
-
-def _create_nat_match_obj(**kwargs):
-    nat_match_obj = {'ethertype': 'IPv4'}
-    delta = set(kwargs.keys()) - set(MATCH_KEYS)
-    if delta:
-        raise Exception(_("Invalid keys for NAT match: %s"), delta)
-    nat_match_obj.update(kwargs)
-    return nat_match_obj
-
-
-def _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj):
-    LOG.debug(_("Creating NAT rule: %s"), nat_rule_obj)
-    uri = _build_uri_path(LROUTERNAT_RESOURCE, parent_resource_id=router_id)
-    return do_request(HTTP_POST, uri, json.dumps(nat_rule_obj),
-                      cluster=cluster)
-
-
-def _build_snat_rule_obj(min_src_ip, max_src_ip, nat_match_obj):
-    return {"to_source_ip_address_min": min_src_ip,
-            "to_source_ip_address_max": max_src_ip,
-            "type": "SourceNatRule",
-            "match": nat_match_obj}
-
-
-def create_lrouter_nosnat_rule_v2(cluster, _router_id, _match_criteria=None):
-    LOG.info(_("No SNAT rules cannot be applied as they are not available in "
-               "this version of the NVP platform"))
-
-
-def create_lrouter_nodnat_rule_v2(cluster, _router_id, _match_criteria=None):
-    LOG.info(_("No DNAT rules cannot be applied as they are not available in "
-               "this version of the NVP platform"))
-
-
-def create_lrouter_snat_rule_v2(cluster, router_id,
-                                min_src_ip, max_src_ip, match_criteria=None):
-
-    nat_match_obj = _create_nat_match_obj(**match_criteria)
-    nat_rule_obj = _build_snat_rule_obj(min_src_ip, max_src_ip, nat_match_obj)
-    return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
-
-
-def create_lrouter_dnat_rule_v2(cluster, router_id, dst_ip,
-                                to_dst_port=None, match_criteria=None):
-
-    nat_match_obj = _create_nat_match_obj(**match_criteria)
-    nat_rule_obj = {
-        "to_destination_ip_address_min": dst_ip,
-        "to_destination_ip_address_max": dst_ip,
-        "type": "DestinationNatRule",
-        "match": nat_match_obj
-    }
-    if to_dst_port:
-        nat_rule_obj['to_destination_port'] = to_dst_port
-    return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
-
-
-def create_lrouter_nosnat_rule_v3(cluster, router_id, order=None,
-                                  match_criteria=None):
-    nat_match_obj = _create_nat_match_obj(**match_criteria)
-    nat_rule_obj = {
-        "type": "NoSourceNatRule",
-        "match": nat_match_obj
-    }
-    if order:
-        nat_rule_obj['order'] = order
-    return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
-
-
-def create_lrouter_nodnat_rule_v3(cluster, router_id, order=None,
-                                  match_criteria=None):
-    nat_match_obj = _create_nat_match_obj(**match_criteria)
-    nat_rule_obj = {
-        "type": "NoDestinationNatRule",
-        "match": nat_match_obj
-    }
-    if order:
-        nat_rule_obj['order'] = order
-    return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
-
-
-def create_lrouter_snat_rule_v3(cluster, router_id, min_src_ip, max_src_ip,
-                                order=None, match_criteria=None):
-    nat_match_obj = _create_nat_match_obj(**match_criteria)
-    nat_rule_obj = _build_snat_rule_obj(min_src_ip, max_src_ip, nat_match_obj)
-    if order:
-        nat_rule_obj['order'] = order
-    return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
-
-
-def create_lrouter_dnat_rule_v3(cluster, router_id, dst_ip, to_dst_port=None,
-                                order=None, match_criteria=None):
-
-    nat_match_obj = _create_nat_match_obj(**match_criteria)
-    nat_rule_obj = {
-        "to_destination_ip_address": dst_ip,
-        "type": "DestinationNatRule",
-        "match": nat_match_obj
-    }
-    if to_dst_port:
-        nat_rule_obj['to_destination_port'] = to_dst_port
-    if order:
-        nat_rule_obj['order'] = order
-    return _create_lrouter_nat_rule(cluster, router_id, nat_rule_obj)
-
-
-@version_dependent
-def create_lrouter_dnat_rule(cluster, *args, **kwargs):
-    pass
-
-
-@version_dependent
-def create_lrouter_snat_rule(cluster, *args, **kwargs):
-    pass
-
-
-@version_dependent
-def create_lrouter_nosnat_rule(cluster, *args, **kwargs):
-    pass
-
-
-@version_dependent
-def create_lrouter_nodnat_rule(cluster, *args, **kwargs):
-    pass
-
-
-def delete_nat_rules_by_match(cluster, router_id, rule_type,
-                              max_num_expected,
-                              min_num_expected=0,
-                              **kwargs):
-    # remove nat rules
-    nat_rules = query_nat_rules(cluster, router_id)
-    to_delete_ids = []
-    for r in nat_rules:
-        if (r['type'] != rule_type):
-            continue
-
-        for key, value in kwargs.iteritems():
-            if not (key in r['match'] and r['match'][key] == value):
-                break
-        else:
-            to_delete_ids.append(r['uuid'])
-    if not (len(to_delete_ids) in
-            range(min_num_expected, max_num_expected + 1)):
-        raise nvp_exc.NvpNatRuleMismatch(actual_rules=len(to_delete_ids),
-                                         min_rules=min_num_expected,
-                                         max_rules=max_num_expected)
-
-    for rule_id in to_delete_ids:
-        delete_router_nat_rule(cluster, router_id, rule_id)
-
-
-def delete_router_nat_rule(cluster, router_id, rule_id):
-    uri = _build_uri_path(LROUTERNAT_RESOURCE, rule_id, router_id)
-    do_request(HTTP_DELETE, uri, cluster=cluster)
-
-
-def query_nat_rules(cluster, router_id, fields="*", filters=None):
-    uri = _build_uri_path(LROUTERNAT_RESOURCE, parent_resource_id=router_id,
-                          fields=fields, filters=filters)
-    return get_all_query_pages(uri, cluster)
-
-
-# NOTE(salvatore-orlando): The following FIXME applies in general to
-# each operation on list attributes.
-# FIXME(salvatore-orlando): need a lock around the list of IPs on an iface
-def update_lrouter_port_ips(cluster, lrouter_id, lport_id,
-                            ips_to_add, ips_to_remove):
-    uri = _build_uri_path(LROUTERPORT_RESOURCE, lport_id, lrouter_id)
-    try:
-        port = do_request(HTTP_GET, uri, cluster=cluster)
-        # TODO(salvatore-orlando): Enforce ips_to_add intersection with
-        # ips_to_remove is empty
-        ip_address_set = set(port['ip_addresses'])
-        ip_address_set = ip_address_set - set(ips_to_remove)
-        ip_address_set = ip_address_set | set(ips_to_add)
-        # Set is not JSON serializable - convert to list
-        port['ip_addresses'] = list(ip_address_set)
-        do_request(HTTP_PUT, uri, json.dumps(port), cluster=cluster)
-    except exception.NotFound as e:
-        # FIXME(salv-orlando):avoid raising different exception
-        data = {'lport_id': lport_id, 'lrouter_id': lrouter_id}
-        msg = (_("Router Port %(lport_id)s not found on router "
-                 "%(lrouter_id)s") % data)
-        LOG.exception(msg)
-        raise nvp_exc.NvpPluginException(err_msg=msg)
-    except NvpApiClient.NvpApiException as e:
-        msg = _("An exception occurred while updating IP addresses on a "
-                "router logical port:%s") % str(e)
-        LOG.exception(msg)
-        raise nvp_exc.NvpPluginException(err_msg=msg)
-
-
-DEFAULT = -1
-NVPLIB_FUNC_DICT = {
-    'create_lrouter': {
-        2: {DEFAULT: create_implicit_routing_lrouter, },
-        3: {DEFAULT: create_implicit_routing_lrouter,
-            1: create_implicit_routing_lrouter_with_distribution,
-            2: create_explicit_routing_lrouter, }, },
-    'update_lrouter': {
-        2: {DEFAULT: update_implicit_routing_lrouter, },
-        3: {DEFAULT: update_implicit_routing_lrouter,
-            2: update_explicit_routing_lrouter, }, },
-    'create_lrouter_dnat_rule': {
-        2: {DEFAULT: create_lrouter_dnat_rule_v2, },
-        3: {DEFAULT: create_lrouter_dnat_rule_v3, }, },
-    'create_lrouter_snat_rule': {
-        2: {DEFAULT: create_lrouter_snat_rule_v2, },
-        3: {DEFAULT: create_lrouter_snat_rule_v3, }, },
-    'create_lrouter_nosnat_rule': {
-        2: {DEFAULT: create_lrouter_nosnat_rule_v2, },
-        3: {DEFAULT: create_lrouter_nosnat_rule_v3, }, },
-    'create_lrouter_nodnat_rule': {
-        2: {DEFAULT: create_lrouter_nodnat_rule_v2, },
-        3: {DEFAULT: create_lrouter_nodnat_rule_v3, }, },
-    'get_default_route_explicit_routing_lrouter': {
-        3: {DEFAULT: get_default_route_explicit_routing_lrouter_v32,
-            2: get_default_route_explicit_routing_lrouter_v32, }, },
-}
-
-
-def get_function_by_version(func_name, nvp_ver):
-    if nvp_ver:
-        if nvp_ver.major not in NVPLIB_FUNC_DICT[func_name]:
-            major = max(NVPLIB_FUNC_DICT[func_name].keys())
-            minor = max(NVPLIB_FUNC_DICT[func_name][major].keys())
-            if major > nvp_ver.major:
-                raise NotImplementedError(_("Operation may not be supported"))
-        else:
-            major = nvp_ver.major
-            minor = nvp_ver.minor
-            if nvp_ver.minor not in NVPLIB_FUNC_DICT[func_name][major]:
-                minor = DEFAULT
-        return NVPLIB_FUNC_DICT[func_name][major][minor]
-    else:
-        msg = _('NVP version is not set. Unable to complete request '
-                'correctly. Check log for NVP communication errors.')
-        raise NvpApiClient.ServiceUnavailable(message=msg)
diff --git a/neutron/tests/unit/nicira/nsxlib/test_router.py b/neutron/tests/unit/nicira/nsxlib/test_router.py
new file mode 100644 (file)
index 0000000..59a9e74
--- /dev/null
@@ -0,0 +1,922 @@
+# Copyright (c) 2014 VMware, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import mock
+
+from neutron.common import exceptions
+from neutron.openstack.common import uuidutils
+from neutron.plugins.nicira.common import exceptions as nvp_exc
+from neutron.plugins.nicira.nsxlib import router as routerlib
+from neutron.plugins.nicira import NvpApiClient
+from neutron.plugins.nicira import nvplib
+from neutron.tests.unit.nicira.test_nvplib import NsxlibNegativeBaseTestCase
+from neutron.tests.unit.nicira.test_nvplib import NvplibTestCase
+from neutron.tests.unit import test_api_v2
+
+_uuid = test_api_v2._uuid
+
+
+class TestNatRules(NvplibTestCase):
+
+    def _test_create_lrouter_dnat_rule(self, version):
+        with mock.patch.object(self.fake_cluster.api_client,
+                               'get_nvp_version',
+                               new=lambda: NvpApiClient.NVPVersion(version)):
+            tenant_id = 'pippo'
+            lrouter = routerlib.create_lrouter(self.fake_cluster,
+                                               uuidutils.generate_uuid(),
+                                               tenant_id,
+                                               'fake_router',
+                                               '192.168.0.1')
+            nat_rule = routerlib.create_lrouter_dnat_rule(
+                self.fake_cluster, lrouter['uuid'], '10.0.0.99',
+                match_criteria={'destination_ip_addresses':
+                                '192.168.0.5'})
+            uri = nvplib._build_uri_path(routerlib.LROUTERNAT_RESOURCE,
+                                         nat_rule['uuid'],
+                                         lrouter['uuid'])
+            resp_obj = nvplib.do_request("GET", uri, cluster=self.fake_cluster)
+            self.assertEqual('DestinationNatRule', resp_obj['type'])
+            self.assertEqual('192.168.0.5',
+                             resp_obj['match']['destination_ip_addresses'])
+
+    def test_create_lrouter_dnat_rule_v2(self):
+        self._test_create_lrouter_dnat_rule('2.9')
+
+    def test_create_lrouter_dnat_rule_v31(self):
+        self._test_create_lrouter_dnat_rule('3.1')
+
+
+class TestExplicitLRouters(NvplibTestCase):
+
+    def setUp(self):
+        self.fake_version = '3.2'
+        super(TestExplicitLRouters, self).setUp()
+
+    def _get_lrouter(self, tenant_id, router_name, router_id, relations=None):
+        schema = '/ws.v1/schema/RoutingTableRoutingConfig'
+
+        router = {'display_name': router_name,
+                  'uuid': router_id,
+                  'tags': [{'scope': 'quantum', 'tag': nvplib.NEUTRON_VERSION},
+                           {'scope': 'os_tid', 'tag': '%s' % tenant_id}],
+                  'distributed': False,
+                  'routing_config': {'type': 'RoutingTableRoutingConfig',
+                                     '_schema': schema},
+                  '_schema': schema,
+                  'nat_synchronization_enabled': True,
+                  'replication_mode': 'service',
+                  'type': 'LogicalRouterConfig',
+                  '_href': '/ws.v1/lrouter/%s' % router_id, }
+        if relations:
+            router['_relations'] = relations
+        return router
+
+    def _get_single_route(self, router_id, route_id='fake_route_id_0',
+                          prefix='0.0.0.0/0', next_hop_ip='1.1.1.1'):
+        return {'protocol': 'static',
+                '_href': '/ws.v1/lrouter/%s/rib/%s' % (router_id, route_id),
+                'prefix': prefix,
+                '_schema': '/ws.v1/schema/RoutingTableEntry',
+                'next_hop_ip': next_hop_ip,
+                'action': 'accept',
+                'uuid': route_id}
+
+    def test_prepare_body_with_implicit_routing_config(self):
+        router_name = 'fake_router_name'
+        tenant_id = 'fake_tenant_id'
+        neutron_router_id = 'pipita_higuain'
+        router_type = 'SingleDefaultRouteImplicitRoutingConfig'
+        route_config = {
+            'default_route_next_hop': {'gateway_ip_address': 'fake_address',
+                                       'type': 'RouterNextHop'}, }
+        body = routerlib._prepare_lrouter_body(router_name, neutron_router_id,
+                                               tenant_id, router_type,
+                                               **route_config)
+        expected = {'display_name': 'fake_router_name',
+                    'routing_config': {
+                        'default_route_next_hop':
+                        {'gateway_ip_address': 'fake_address',
+                         'type': 'RouterNextHop'},
+                        'type': 'SingleDefaultRouteImplicitRoutingConfig'},
+                    'tags': [{'scope': 'os_tid', 'tag': 'fake_tenant_id'},
+                             {'scope': 'q_router_id', 'tag': 'pipita_higuain'},
+                             {'scope': 'quantum',
+                              'tag': nvplib.NEUTRON_VERSION}],
+                    'type': 'LogicalRouterConfig'}
+        self.assertEqual(expected, body)
+
+    def test_prepare_body_without_routing_config(self):
+        router_name = 'fake_router_name'
+        tenant_id = 'fake_tenant_id'
+        neutron_router_id = 'marekiaro_hamsik'
+        router_type = 'RoutingTableRoutingConfig'
+        body = routerlib._prepare_lrouter_body(router_name, neutron_router_id,
+                                               tenant_id, router_type)
+        expected = {'display_name': 'fake_router_name',
+                    'routing_config': {'type': 'RoutingTableRoutingConfig'},
+                    'tags': [{'scope': 'os_tid', 'tag': 'fake_tenant_id'},
+                             {'scope': 'q_router_id',
+                              'tag': 'marekiaro_hamsik'},
+                             {'scope': 'quantum',
+                              'tag': nvplib.NEUTRON_VERSION}],
+                    'type': 'LogicalRouterConfig'}
+        self.assertEqual(expected, body)
+
+    def test_get_lrouter(self):
+        tenant_id = 'fake_tenant_id'
+        router_name = 'fake_router_name'
+        router_id = 'fake_router_id'
+        relations = {
+            'LogicalRouterStatus':
+            {'_href': '/ws.v1/lrouter/%s/status' % router_id,
+             'lport_admin_up_count': 1,
+             '_schema': '/ws.v1/schema/LogicalRouterStatus',
+             'lport_count': 1,
+             'fabric_status': True,
+             'type': 'LogicalRouterStatus',
+             'lport_link_up_count': 0, }, }
+
+        with mock.patch.object(routerlib, 'do_request',
+                               return_value=self._get_lrouter(tenant_id,
+                                                              router_name,
+                                                              router_id,
+                                                              relations)):
+            lrouter = routerlib.get_lrouter(self.fake_cluster, router_id)
+            self.assertTrue(
+                lrouter['_relations']['LogicalRouterStatus']['fabric_status'])
+
+    def test_create_lrouter(self):
+        tenant_id = 'fake_tenant_id'
+        router_name = 'fake_router_name'
+        router_id = 'fake_router_id'
+        nexthop_ip = '10.0.0.1'
+        with mock.patch.object(
+            routerlib, 'do_request',
+            return_value=self._get_lrouter(tenant_id,
+                                           router_name,
+                                           router_id)):
+            lrouter = routerlib.create_lrouter(self.fake_cluster,
+                                               uuidutils.generate_uuid(),
+                                               tenant_id,
+                                               router_name, nexthop_ip)
+            self.assertEqual(lrouter['routing_config']['type'],
+                             'RoutingTableRoutingConfig')
+            self.assertNotIn('default_route_next_hop',
+                             lrouter['routing_config'])
+
+    def test_update_lrouter_with_no_routes(self):
+        router_id = 'fake_router_id'
+        new_routes = [{"nexthop": "10.0.0.2",
+                       "destination": "169.254.169.0/30"}, ]
+
+        nvp_routes = [self._get_single_route(router_id)]
+        with mock.patch.object(routerlib, 'get_explicit_routes_lrouter',
+                               return_value=nvp_routes):
+            with mock.patch.object(routerlib, 'create_explicit_route_lrouter',
+                                   return_value='fake_uuid'):
+                old_routes = routerlib.update_explicit_routes_lrouter(
+                    self.fake_cluster, router_id, new_routes)
+        self.assertEqual(old_routes, nvp_routes)
+
+    def test_update_lrouter_with_no_routes_raise_nsx_exception(self):
+        router_id = 'fake_router_id'
+        new_routes = [{"nexthop": "10.0.0.2",
+                       "destination": "169.254.169.0/30"}, ]
+
+        nsx_routes = [self._get_single_route(router_id)]
+        with mock.patch.object(routerlib, 'get_explicit_routes_lrouter',
+                               return_value=nsx_routes):
+            with mock.patch.object(routerlib, 'create_explicit_route_lrouter',
+                                   side_effect=NvpApiClient.NvpApiException):
+                self.assertRaises(NvpApiClient.NvpApiException,
+                                  routerlib.update_explicit_routes_lrouter,
+                                  self.fake_cluster, router_id, new_routes)
+
+    def test_update_lrouter_with_routes(self):
+        router_id = 'fake_router_id'
+        new_routes = [{"next_hop_ip": "10.0.0.2",
+                       "prefix": "169.254.169.0/30"}, ]
+
+        nsx_routes = [self._get_single_route(router_id),
+                      self._get_single_route(router_id, 'fake_route_id_1',
+                                             '0.0.0.1/24', '10.0.0.3'),
+                      self._get_single_route(router_id, 'fake_route_id_2',
+                                             '0.0.0.2/24', '10.0.0.4'), ]
+
+        with mock.patch.object(routerlib, 'get_explicit_routes_lrouter',
+                               return_value=nsx_routes):
+            with mock.patch.object(routerlib, 'delete_explicit_route_lrouter',
+                                   return_value=None):
+                with mock.patch.object(routerlib,
+                                       'create_explicit_route_lrouter',
+                                       return_value='fake_uuid'):
+                    old_routes = routerlib.update_explicit_routes_lrouter(
+                        self.fake_cluster, router_id, new_routes)
+        self.assertEqual(old_routes, nsx_routes)
+
+    def test_update_lrouter_with_routes_raises_nsx_expception(self):
+        router_id = 'fake_router_id'
+        new_routes = [{"nexthop": "10.0.0.2",
+                       "destination": "169.254.169.0/30"}, ]
+
+        nsx_routes = [self._get_single_route(router_id),
+                      self._get_single_route(router_id, 'fake_route_id_1',
+                                             '0.0.0.1/24', '10.0.0.3'),
+                      self._get_single_route(router_id, 'fake_route_id_2',
+                                             '0.0.0.2/24', '10.0.0.4'), ]
+
+        with mock.patch.object(routerlib, 'get_explicit_routes_lrouter',
+                               return_value=nsx_routes):
+            with mock.patch.object(routerlib, 'delete_explicit_route_lrouter',
+                                   side_effect=NvpApiClient.NvpApiException):
+                with mock.patch.object(
+                    routerlib, 'create_explicit_route_lrouter',
+                    return_value='fake_uuid'):
+                    self.assertRaises(
+                        NvpApiClient.NvpApiException,
+                        routerlib.update_explicit_routes_lrouter,
+                        self.fake_cluster, router_id, new_routes)
+
+
+class RouterNegativeTestCase(NsxlibNegativeBaseTestCase):
+
+    def test_create_lrouter_on_failure(self):
+        self.assertRaises(nvplib.NvpApiClient.NvpApiException,
+                          routerlib.create_lrouter,
+                          self.fake_cluster,
+                          uuidutils.generate_uuid(),
+                          'pluto',
+                          'fake_router',
+                          'my_hop')
+
+    def test_delete_lrouter_on_failure(self):
+        self.assertRaises(nvplib.NvpApiClient.NvpApiException,
+                          routerlib.delete_lrouter,
+                          self.fake_cluster,
+                          'fake_router')
+
+    def test_get_lrouter_on_failure(self):
+        self.assertRaises(nvplib.NvpApiClient.NvpApiException,
+                          routerlib.get_lrouter,
+                          self.fake_cluster,
+                          'fake_router')
+
+    def test_update_lrouter_on_failure(self):
+        self.assertRaises(nvplib.NvpApiClient.NvpApiException,
+                          routerlib.update_lrouter,
+                          self.fake_cluster,
+                          'fake_router',
+                          'pluto',
+                          'new_hop')
+
+
+class TestLogicalRouters(NvplibTestCase):
+
+    def _verify_lrouter(self, res_lrouter,
+                        expected_uuid,
+                        expected_display_name,
+                        expected_nexthop,
+                        expected_tenant_id,
+                        expected_neutron_id=None,
+                        expected_distributed=None):
+        self.assertEqual(res_lrouter['uuid'], expected_uuid)
+        nexthop = (res_lrouter['routing_config']
+                   ['default_route_next_hop']['gateway_ip_address'])
+        self.assertEqual(nexthop, expected_nexthop)
+        router_tags = self._build_tag_dict(res_lrouter['tags'])
+        self.assertIn('os_tid', router_tags)
+        self.assertEqual(res_lrouter['display_name'], expected_display_name)
+        self.assertEqual(expected_tenant_id, router_tags['os_tid'])
+        if expected_distributed is not None:
+            self.assertEqual(expected_distributed,
+                             res_lrouter['distributed'])
+        if expected_neutron_id:
+            self.assertIn('q_router_id', router_tags)
+            self.assertEqual(expected_neutron_id, router_tags['q_router_id'])
+
+    def test_get_lrouters(self):
+        lrouter_uuids = [routerlib.create_lrouter(
+            self.fake_cluster, 'whatever', 'pippo', 'fake-lrouter-%s' % k,
+            '10.0.0.1')['uuid'] for k in range(3)]
+        routers = routerlib.get_lrouters(self.fake_cluster, 'pippo')
+        for router in routers:
+            self.assertIn(router['uuid'], lrouter_uuids)
+
+    def _create_lrouter(self, version, neutron_id=None, distributed=None):
+        with mock.patch.object(
+            self.fake_cluster.api_client, 'get_nvp_version',
+            return_value=NvpApiClient.NVPVersion(version)):
+            if not neutron_id:
+                neutron_id = uuidutils.generate_uuid()
+            lrouter = routerlib.create_lrouter(
+                self.fake_cluster, neutron_id, 'pippo',
+                'fake-lrouter', '10.0.0.1', distributed=distributed)
+            return routerlib.get_lrouter(self.fake_cluster,
+                                         lrouter['uuid'])
+
+    def test_create_and_get_lrouter_v30(self):
+        neutron_id = uuidutils.generate_uuid()
+        res_lrouter = self._create_lrouter('3.0', neutron_id=neutron_id)
+        self._verify_lrouter(res_lrouter, res_lrouter['uuid'],
+                             'fake-lrouter', '10.0.0.1', 'pippo',
+                             expected_neutron_id=neutron_id)
+
+    def test_create_and_get_lrouter_v31_centralized(self):
+        neutron_id = uuidutils.generate_uuid()
+        res_lrouter = self._create_lrouter('3.1', neutron_id=neutron_id,
+                                           distributed=False)
+        self._verify_lrouter(res_lrouter, res_lrouter['uuid'],
+                             'fake-lrouter', '10.0.0.1', 'pippo',
+                             expected_neutron_id=neutron_id,
+                             expected_distributed=False)
+
+    def test_create_and_get_lrouter_v31_distributed(self):
+        neutron_id = uuidutils.generate_uuid()
+        res_lrouter = self._create_lrouter('3.1', neutron_id=neutron_id,
+                                           distributed=True)
+        self._verify_lrouter(res_lrouter, res_lrouter['uuid'],
+                             'fake-lrouter', '10.0.0.1', 'pippo',
+                             expected_neutron_id=neutron_id,
+                             expected_distributed=True)
+
+    def test_create_and_get_lrouter_name_exceeds_40chars(self):
+        neutron_id = uuidutils.generate_uuid()
+        display_name = '*' * 50
+        lrouter = routerlib.create_lrouter(self.fake_cluster,
+                                           neutron_id,
+                                           'pippo',
+                                           display_name,
+                                           '10.0.0.1')
+        res_lrouter = routerlib.get_lrouter(self.fake_cluster,
+                                            lrouter['uuid'])
+        self._verify_lrouter(res_lrouter, lrouter['uuid'],
+                             '*' * 40, '10.0.0.1', 'pippo',
+                             expected_neutron_id=neutron_id)
+
+    def _test_version_dependent_update_lrouter(self, version):
+        def foo(*args, **kwargs):
+            return version
+
+        foo_func_dict = {
+            'update_lrouter': {
+                2: {-1: foo},
+                3: {-1: foo, 2: foo}
+            }
+        }
+
+        with mock.patch.object(self.fake_cluster.api_client,
+                               'get_nvp_version',
+                               return_value=NvpApiClient.NVPVersion(version)):
+            with mock.patch.dict(routerlib.ROUTER_FUNC_DICT,
+                                 foo_func_dict, clear=True):
+                return routerlib.update_lrouter(
+                    self.fake_cluster, 'foo_router_id', 'foo_router_name',
+                    'foo_nexthop', routes={'foo_destination': 'foo_address'})
+
+    def test_version_dependent_update_lrouter_old_versions(self):
+        self.assertRaises(nvp_exc.NvpInvalidVersion,
+                          self._test_version_dependent_update_lrouter,
+                          "2.9")
+        self.assertRaises(nvp_exc.NvpInvalidVersion,
+                          self._test_version_dependent_update_lrouter,
+                          "3.0")
+        self.assertRaises(nvp_exc.NvpInvalidVersion,
+                          self._test_version_dependent_update_lrouter,
+                          "3.1")
+
+    def test_version_dependent_update_lrouter_new_versions(self):
+        self.assertEqual("3.2",
+                         self._test_version_dependent_update_lrouter("3.2"))
+        self.assertEqual("4.0",
+                         self._test_version_dependent_update_lrouter("4.0"))
+        self.assertEqual("4.1",
+                         self._test_version_dependent_update_lrouter("4.1"))
+
+    def test_update_lrouter_no_nexthop(self):
+        neutron_id = uuidutils.generate_uuid()
+        lrouter = routerlib.create_lrouter(self.fake_cluster,
+                                           neutron_id,
+                                           'pippo',
+                                           'fake-lrouter',
+                                           '10.0.0.1')
+        lrouter = routerlib.update_lrouter(self.fake_cluster,
+                                           lrouter['uuid'],
+                                           'new_name',
+                                           None)
+        res_lrouter = routerlib.get_lrouter(self.fake_cluster,
+                                            lrouter['uuid'])
+        self._verify_lrouter(res_lrouter, lrouter['uuid'],
+                             'new_name', '10.0.0.1', 'pippo',
+                             expected_neutron_id=neutron_id)
+
+    def test_update_lrouter(self):
+        neutron_id = uuidutils.generate_uuid()
+        lrouter = routerlib.create_lrouter(self.fake_cluster,
+                                           neutron_id,
+                                           'pippo',
+                                           'fake-lrouter',
+                                           '10.0.0.1')
+        lrouter = routerlib.update_lrouter(self.fake_cluster,
+                                           lrouter['uuid'],
+                                           'new_name',
+                                           '192.168.0.1')
+        res_lrouter = routerlib.get_lrouter(self.fake_cluster,
+                                            lrouter['uuid'])
+        self._verify_lrouter(res_lrouter, lrouter['uuid'],
+                             'new_name', '192.168.0.1', 'pippo',
+                             expected_neutron_id=neutron_id)
+
+    def test_update_nonexistent_lrouter_raises(self):
+        self.assertRaises(exceptions.NotFound,
+                          routerlib.update_lrouter,
+                          self.fake_cluster,
+                          'whatever',
+                          'foo', '9.9.9.9')
+
+    def test_delete_lrouter(self):
+        lrouter = routerlib.create_lrouter(self.fake_cluster,
+                                           uuidutils.generate_uuid(),
+                                           'pippo',
+                                           'fake-lrouter',
+                                           '10.0.0.1')
+        routerlib.delete_lrouter(self.fake_cluster, lrouter['uuid'])
+        self.assertRaises(exceptions.NotFound,
+                          routerlib.get_lrouter,
+                          self.fake_cluster,
+                          lrouter['uuid'])
+
+    def test_query_lrouter_ports(self):
+        lrouter = routerlib.create_lrouter(self.fake_cluster,
+                                           uuidutils.generate_uuid(),
+                                           'pippo',
+                                           'fake-lrouter',
+                                           '10.0.0.1')
+        router_port_uuids = [routerlib.create_router_lport(
+            self.fake_cluster, lrouter['uuid'], 'pippo',
+            'qp_id_%s' % k, 'port-%s' % k, True,
+            ['192.168.0.%s' % k], '00:11:22:33:44:55')['uuid']
+            for k in range(3)]
+        ports = routerlib.query_lrouter_lports(
+            self.fake_cluster, lrouter['uuid'])
+        self.assertEqual(len(ports), 3)
+        for res_port in ports:
+            self.assertIn(res_port['uuid'], router_port_uuids)
+
+    def test_query_lrouter_lports_nonexistent_lrouter_raises(self):
+        self.assertRaises(
+            exceptions.NotFound, routerlib.create_router_lport,
+            self.fake_cluster, 'booo', 'pippo', 'neutron_port_id',
+            'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
+
+    def test_create_and_get_lrouter_port(self):
+        lrouter = routerlib.create_lrouter(self.fake_cluster,
+                                           uuidutils.generate_uuid(),
+                                           'pippo',
+                                           'fake-lrouter',
+                                           '10.0.0.1')
+        routerlib.create_router_lport(
+            self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
+            'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
+        ports = routerlib.query_lrouter_lports(
+            self.fake_cluster, lrouter['uuid'])
+        self.assertEqual(len(ports), 1)
+        res_port = ports[0]
+        port_tags = self._build_tag_dict(res_port['tags'])
+        self.assertEqual(['192.168.0.1'], res_port['ip_addresses'])
+        self.assertIn('os_tid', port_tags)
+        self.assertIn('q_port_id', port_tags)
+        self.assertEqual('pippo', port_tags['os_tid'])
+        self.assertEqual('neutron_port_id', port_tags['q_port_id'])
+
+    def test_create_lrouter_port_nonexistent_router_raises(self):
+        self.assertRaises(
+            exceptions.NotFound, routerlib.create_router_lport,
+            self.fake_cluster, 'booo', 'pippo', 'neutron_port_id',
+            'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
+
+    def test_update_lrouter_port(self):
+        lrouter = routerlib.create_lrouter(self.fake_cluster,
+                                           uuidutils.generate_uuid(),
+                                           'pippo',
+                                           'fake-lrouter',
+                                           '10.0.0.1')
+        lrouter_port = routerlib.create_router_lport(
+            self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
+            'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
+        routerlib.update_router_lport(
+            self.fake_cluster, lrouter['uuid'], lrouter_port['uuid'],
+            'pippo', 'another_port_id', 'name', False,
+            ['192.168.0.1', '10.10.10.254'])
+
+        ports = routerlib.query_lrouter_lports(
+            self.fake_cluster, lrouter['uuid'])
+        self.assertEqual(len(ports), 1)
+        res_port = ports[0]
+        port_tags = self._build_tag_dict(res_port['tags'])
+        self.assertEqual(['192.168.0.1', '10.10.10.254'],
+                         res_port['ip_addresses'])
+        self.assertEqual('False', res_port['admin_status_enabled'])
+        self.assertIn('os_tid', port_tags)
+        self.assertIn('q_port_id', port_tags)
+        self.assertEqual('pippo', port_tags['os_tid'])
+        self.assertEqual('another_port_id', port_tags['q_port_id'])
+
+    def test_update_lrouter_port_nonexistent_router_raises(self):
+        self.assertRaises(
+            exceptions.NotFound, routerlib.update_router_lport,
+            self.fake_cluster, 'boo-router', 'boo-port', 'pippo',
+            'neutron_port_id', 'name', True, ['192.168.0.1'])
+
+    def test_update_lrouter_port_nonexistent_port_raises(self):
+        lrouter = routerlib.create_lrouter(self.fake_cluster,
+                                           uuidutils.generate_uuid(),
+                                           'pippo',
+                                           'fake-lrouter',
+                                           '10.0.0.1')
+        self.assertRaises(
+            exceptions.NotFound, routerlib.update_router_lport,
+            self.fake_cluster, lrouter['uuid'], 'boo-port', 'pippo',
+            'neutron_port_id', 'name', True, ['192.168.0.1'])
+
+    def test_delete_lrouter_port(self):
+        lrouter = routerlib.create_lrouter(self.fake_cluster,
+                                           uuidutils.generate_uuid(),
+                                           'pippo',
+                                           'fake-lrouter',
+                                           '10.0.0.1')
+        lrouter_port = routerlib.create_router_lport(
+            self.fake_cluster, lrouter['uuid'], 'pippo', 'x', 'y', True, [],
+            '00:11:22:33:44:55')
+        ports = routerlib.query_lrouter_lports(
+            self.fake_cluster, lrouter['uuid'])
+        self.assertEqual(len(ports), 1)
+        routerlib.delete_router_lport(self.fake_cluster, lrouter['uuid'],
+                                      lrouter_port['uuid'])
+        ports = routerlib.query_lrouter_lports(
+            self.fake_cluster, lrouter['uuid'])
+        self.assertFalse(len(ports))
+
+    def test_delete_lrouter_port_nonexistent_router_raises(self):
+        self.assertRaises(exceptions.NotFound,
+                          routerlib.delete_router_lport,
+                          self.fake_cluster, 'xyz', 'abc')
+
+    def test_delete_lrouter_port_nonexistent_port_raises(self):
+        lrouter = routerlib.create_lrouter(self.fake_cluster,
+                                           uuidutils.generate_uuid(),
+                                           'pippo',
+                                           'fake-lrouter',
+                                           '10.0.0.1')
+        self.assertRaises(exceptions.NotFound,
+                          routerlib.delete_router_lport,
+                          self.fake_cluster, lrouter['uuid'], 'abc')
+
+    def test_delete_peer_lrouter_port(self):
+        lrouter = routerlib.create_lrouter(self.fake_cluster,
+                                           uuidutils.generate_uuid(),
+                                           'pippo',
+                                           'fake-lrouter',
+                                           '10.0.0.1')
+        lrouter_port = routerlib.create_router_lport(
+            self.fake_cluster, lrouter['uuid'], 'pippo', 'x', 'y', True, [],
+            '00:11:22:33:44:55')
+
+        def fakegetport(*args, **kwargs):
+            return {'_relations': {'LogicalPortAttachment':
+                                   {'peer_port_uuid': lrouter_port['uuid']}}}
+        # mock get_port
+        with mock.patch.object(routerlib, 'get_port', new=fakegetport):
+            routerlib.delete_peer_router_lport(self.fake_cluster,
+                                               lrouter_port['uuid'],
+                                               'whatwever', 'whatever')
+
+    def test_update_lrouter_port_ips_add_only(self):
+        lrouter = routerlib.create_lrouter(self.fake_cluster,
+                                           uuidutils.generate_uuid(),
+                                           'pippo',
+                                           'fake-lrouter',
+                                           '10.0.0.1')
+        lrouter_port = routerlib.create_router_lport(
+            self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
+            'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
+        routerlib.update_lrouter_port_ips(
+            self.fake_cluster, lrouter['uuid'], lrouter_port['uuid'],
+            ['10.10.10.254'], [])
+        ports = routerlib.query_lrouter_lports(
+            self.fake_cluster, lrouter['uuid'])
+        self.assertEqual(len(ports), 1)
+        res_port = ports[0]
+        self.assertEqual(['10.10.10.254', '192.168.0.1'],
+                         res_port['ip_addresses'])
+
+    def test_update_lrouter_port_ips_remove_only(self):
+        lrouter = routerlib.create_lrouter(self.fake_cluster,
+                                           uuidutils.generate_uuid(),
+                                           'pippo',
+                                           'fake-lrouter',
+                                           '10.0.0.1')
+        lrouter_port = routerlib.create_router_lport(
+            self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
+            'name', True, ['192.168.0.1', '10.10.10.254'],
+            '00:11:22:33:44:55')
+        routerlib.update_lrouter_port_ips(
+            self.fake_cluster, lrouter['uuid'], lrouter_port['uuid'],
+            [], ['10.10.10.254'])
+        ports = routerlib.query_lrouter_lports(
+            self.fake_cluster, lrouter['uuid'])
+        self.assertEqual(len(ports), 1)
+        res_port = ports[0]
+        self.assertEqual(['192.168.0.1'], res_port['ip_addresses'])
+
+    def test_update_lrouter_port_ips_add_and_remove(self):
+        lrouter = routerlib.create_lrouter(self.fake_cluster,
+                                           uuidutils.generate_uuid(),
+                                           'pippo',
+                                           'fake-lrouter',
+                                           '10.0.0.1')
+        lrouter_port = routerlib.create_router_lport(
+            self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
+            'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
+        routerlib.update_lrouter_port_ips(
+            self.fake_cluster, lrouter['uuid'], lrouter_port['uuid'],
+            ['10.10.10.254'], ['192.168.0.1'])
+        ports = routerlib.query_lrouter_lports(
+            self.fake_cluster, lrouter['uuid'])
+        self.assertEqual(len(ports), 1)
+        res_port = ports[0]
+        self.assertEqual(['10.10.10.254'], res_port['ip_addresses'])
+
+    def test_update_lrouter_port_ips_nonexistent_router_raises(self):
+        self.assertRaises(
+            nvp_exc.NvpPluginException, routerlib.update_lrouter_port_ips,
+            self.fake_cluster, 'boo-router', 'boo-port', [], [])
+
+    def test_update_lrouter_port_ips_nsx_exception_raises(self):
+        lrouter = routerlib.create_lrouter(self.fake_cluster,
+                                           uuidutils.generate_uuid(),
+                                           'pippo',
+                                           'fake-lrouter',
+                                           '10.0.0.1')
+        lrouter_port = routerlib.create_router_lport(
+            self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
+            'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
+
+        def raise_nsx_exc(*args, **kwargs):
+            raise NvpApiClient.NvpApiException()
+
+        with mock.patch.object(routerlib, 'do_request', new=raise_nsx_exc):
+            self.assertRaises(
+                nvp_exc.NvpPluginException, routerlib.update_lrouter_port_ips,
+                self.fake_cluster, lrouter['uuid'],
+                lrouter_port['uuid'], [], [])
+
+    def test_plug_lrouter_port_patch_attachment(self):
+        tenant_id = 'pippo'
+        transport_zones_config = [{'zone_uuid': _uuid(),
+                                   'transport_type': 'stt'}]
+        lswitch = nvplib.create_lswitch(self.fake_cluster,
+                                        _uuid(),
+                                        tenant_id, 'fake-switch',
+                                        transport_zones_config)
+        lport = nvplib.create_lport(self.fake_cluster, lswitch['uuid'],
+                                    tenant_id, 'xyz',
+                                    'name', 'device_id', True)
+        lrouter = routerlib.create_lrouter(self.fake_cluster,
+                                           uuidutils.generate_uuid(),
+                                           tenant_id,
+                                           'fake-lrouter',
+                                           '10.0.0.1')
+        lrouter_port = routerlib.create_router_lport(
+            self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
+            'name', True, ['192.168.0.1'], '00:11:22:33:44:55:66')
+        result = routerlib.plug_router_port_attachment(
+            self.fake_cluster, lrouter['uuid'],
+            lrouter_port['uuid'],
+            lport['uuid'], 'PatchAttachment')
+        self.assertEqual(lport['uuid'],
+                         result['LogicalPortAttachment']['peer_port_uuid'])
+
+    def test_plug_lrouter_port_l3_gw_attachment(self):
+        lrouter = routerlib.create_lrouter(self.fake_cluster,
+                                           uuidutils.generate_uuid(),
+                                           'pippo',
+                                           'fake-lrouter',
+                                           '10.0.0.1')
+        lrouter_port = routerlib.create_router_lport(
+            self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
+            'name', True, ['192.168.0.1'], '00:11:22:33:44:55:66')
+        result = routerlib.plug_router_port_attachment(
+            self.fake_cluster, lrouter['uuid'],
+            lrouter_port['uuid'],
+            'gw_att', 'L3GatewayAttachment')
+        self.assertEqual(
+            'gw_att',
+            result['LogicalPortAttachment']['l3_gateway_service_uuid'])
+
+    def test_plug_lrouter_port_l3_gw_attachment_with_vlan(self):
+        lrouter = routerlib.create_lrouter(self.fake_cluster,
+                                           uuidutils.generate_uuid(),
+                                           'pippo',
+                                           'fake-lrouter',
+                                           '10.0.0.1')
+        lrouter_port = routerlib.create_router_lport(
+            self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
+            'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
+        result = routerlib.plug_router_port_attachment(
+            self.fake_cluster, lrouter['uuid'],
+            lrouter_port['uuid'],
+            'gw_att', 'L3GatewayAttachment', 123)
+        self.assertEqual(
+            'gw_att',
+            result['LogicalPortAttachment']['l3_gateway_service_uuid'])
+        self.assertEqual(
+            '123',
+            result['LogicalPortAttachment']['vlan_id'])
+
+    def test_plug_lrouter_port_invalid_attachment_type_raises(self):
+        lrouter = routerlib.create_lrouter(self.fake_cluster,
+                                           uuidutils.generate_uuid(),
+                                           'pippo',
+                                           'fake-lrouter',
+                                           '10.0.0.1')
+        lrouter_port = routerlib.create_router_lport(
+            self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
+            'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
+        self.assertRaises(nvp_exc.NvpInvalidAttachmentType,
+                          routerlib.plug_router_port_attachment,
+                          self.fake_cluster, lrouter['uuid'],
+                          lrouter_port['uuid'], 'gw_att', 'BadType')
+
+    def _test_create_router_snat_rule(self, version):
+        lrouter = routerlib.create_lrouter(self.fake_cluster,
+                                           uuidutils.generate_uuid(),
+                                           'pippo',
+                                           'fake-lrouter',
+                                           '10.0.0.1')
+        with mock.patch.object(self.fake_cluster.api_client,
+                               'get_nvp_version',
+                               new=lambda: NvpApiClient.NVPVersion(version)):
+            routerlib.create_lrouter_snat_rule(
+                self.fake_cluster, lrouter['uuid'],
+                '10.0.0.2', '10.0.0.2', order=200,
+                match_criteria={'source_ip_addresses': '192.168.0.24'})
+            rules = routerlib.query_nat_rules(
+                self.fake_cluster, lrouter['uuid'])
+            self.assertEqual(len(rules), 1)
+
+    def test_create_router_snat_rule_v3(self):
+        self._test_create_router_snat_rule('3.0')
+
+    def test_create_router_snat_rule_v2(self):
+        self._test_create_router_snat_rule('2.0')
+
+    def _test_create_router_dnat_rule(self, version, dest_port=None):
+        lrouter = routerlib.create_lrouter(self.fake_cluster,
+                                           uuidutils.generate_uuid(),
+                                           'pippo',
+                                           'fake-lrouter',
+                                           '10.0.0.1')
+        with mock.patch.object(self.fake_cluster.api_client,
+                               'get_nvp_version',
+                               return_value=NvpApiClient.NVPVersion(version)):
+            routerlib.create_lrouter_dnat_rule(
+                self.fake_cluster, lrouter['uuid'], '192.168.0.2', order=200,
+                dest_port=dest_port,
+                match_criteria={'destination_ip_addresses': '10.0.0.3'})
+            rules = routerlib.query_nat_rules(
+                self.fake_cluster, lrouter['uuid'])
+            self.assertEqual(len(rules), 1)
+
+    def test_create_router_dnat_rule_v3(self):
+        self._test_create_router_dnat_rule('3.0')
+
+    def test_create_router_dnat_rule_v2(self):
+        self._test_create_router_dnat_rule('2.0')
+
+    def test_create_router_dnat_rule_v2_with_destination_port(self):
+        self._test_create_router_dnat_rule('2.0', 8080)
+
+    def test_create_router_dnat_rule_v3_with_destination_port(self):
+        self._test_create_router_dnat_rule('3.0', 8080)
+
+    def test_create_router_snat_rule_invalid_match_keys_raises(self):
+        # In this case the version does not make a difference
+        lrouter = routerlib.create_lrouter(self.fake_cluster,
+                                           uuidutils.generate_uuid(),
+                                           'pippo',
+                                           'fake-lrouter',
+                                           '10.0.0.1')
+
+        with mock.patch.object(self.fake_cluster.api_client,
+                               'get_nvp_version',
+                               new=lambda: '2.0'):
+            self.assertRaises(AttributeError,
+                              routerlib.create_lrouter_snat_rule,
+                              self.fake_cluster, lrouter['uuid'],
+                              '10.0.0.2', '10.0.0.2', order=200,
+                              match_criteria={'foo': 'bar'})
+
+    def _test_create_router_nosnat_rule(self, version, expected=1):
+        lrouter = routerlib.create_lrouter(self.fake_cluster,
+                                           uuidutils.generate_uuid(),
+                                           'pippo',
+                                           'fake-lrouter',
+                                           '10.0.0.1')
+        with mock.patch.object(self.fake_cluster.api_client,
+                               'get_nvp_version',
+                               new=lambda: NvpApiClient.NVPVersion(version)):
+            routerlib.create_lrouter_nosnat_rule(
+                self.fake_cluster, lrouter['uuid'],
+                order=100,
+                match_criteria={'destination_ip_addresses': '192.168.0.0/24'})
+            rules = routerlib.query_nat_rules(
+                self.fake_cluster, lrouter['uuid'])
+            # NoSNAT rules do not exist in V2
+            self.assertEqual(len(rules), expected)
+
+    def test_create_router_nosnat_rule_v2(self):
+        self._test_create_router_nosnat_rule('2.0', expected=0)
+
+    def test_create_router_nosnat_rule_v3(self):
+        self._test_create_router_nosnat_rule('3.0')
+
+    def _prepare_nat_rules_for_delete_tests(self):
+        lrouter = routerlib.create_lrouter(self.fake_cluster,
+                                           uuidutils.generate_uuid(),
+                                           'pippo',
+                                           'fake-lrouter',
+                                           '10.0.0.1')
+        # v2 or v3 makes no difference for this test
+        with mock.patch.object(self.fake_cluster.api_client,
+                               'get_nvp_version',
+                               new=lambda: NvpApiClient.NVPVersion('2.0')):
+            routerlib.create_lrouter_snat_rule(
+                self.fake_cluster, lrouter['uuid'],
+                '10.0.0.2', '10.0.0.2', order=220,
+                match_criteria={'source_ip_addresses': '192.168.0.0/24'})
+            routerlib.create_lrouter_snat_rule(
+                self.fake_cluster, lrouter['uuid'],
+                '10.0.0.3', '10.0.0.3', order=200,
+                match_criteria={'source_ip_addresses': '192.168.0.2/32'})
+            routerlib.create_lrouter_dnat_rule(
+                self.fake_cluster, lrouter['uuid'], '192.168.0.2', order=200,
+                match_criteria={'destination_ip_addresses': '10.0.0.3'})
+        return lrouter
+
+    def test_delete_router_nat_rules_by_match_on_destination_ip(self):
+        lrouter = self._prepare_nat_rules_for_delete_tests()
+        rules = routerlib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
+        self.assertEqual(len(rules), 3)
+        routerlib.delete_nat_rules_by_match(
+            self.fake_cluster, lrouter['uuid'], 'DestinationNatRule', 1, 1,
+            destination_ip_addresses='10.0.0.3')
+        rules = routerlib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
+        self.assertEqual(len(rules), 2)
+
+    def test_delete_router_nat_rules_by_match_on_source_ip(self):
+        lrouter = self._prepare_nat_rules_for_delete_tests()
+        rules = routerlib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
+        self.assertEqual(len(rules), 3)
+        routerlib.delete_nat_rules_by_match(
+            self.fake_cluster, lrouter['uuid'], 'SourceNatRule', 1, 1,
+            source_ip_addresses='192.168.0.2/32')
+        rules = routerlib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
+        self.assertEqual(len(rules), 2)
+
+    def test_delete_router_nat_rules_by_match_no_match_expected(self):
+        lrouter = self._prepare_nat_rules_for_delete_tests()
+        rules = routerlib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
+        self.assertEqual(len(rules), 3)
+        routerlib.delete_nat_rules_by_match(
+            self.fake_cluster, lrouter['uuid'], 'SomeWeirdType', 0)
+        rules = routerlib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
+        self.assertEqual(len(rules), 3)
+        routerlib.delete_nat_rules_by_match(
+            self.fake_cluster, lrouter['uuid'], 'DestinationNatRule', 0,
+            destination_ip_addresses='99.99.99.99')
+        rules = routerlib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
+        self.assertEqual(len(rules), 3)
+
+    def test_delete_router_nat_rules_by_match_no_match_raises(self):
+        lrouter = self._prepare_nat_rules_for_delete_tests()
+        rules = routerlib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
+        self.assertEqual(len(rules), 3)
+        self.assertRaises(
+            nvp_exc.NvpNatRuleMismatch,
+            routerlib.delete_nat_rules_by_match,
+            self.fake_cluster, lrouter['uuid'],
+            'SomeWeirdType', 1, 1)
diff --git a/neutron/tests/unit/nicira/nsxlib/test_versioning.py b/neutron/tests/unit/nicira/nsxlib/test_versioning.py
new file mode 100644 (file)
index 0000000..072c3f6
--- /dev/null
@@ -0,0 +1,57 @@
+# Copyright (c) 2014 VMware, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+from neutron.plugins.nicira.nsxlib import router as routerlib
+from neutron.plugins.nicira.nsxlib import versioning
+from neutron.plugins.nicira import NvpApiClient
+from neutron.tests import base
+
+
+class TestVersioning(base.BaseTestCase):
+
+    def test_function_handling_missing_minor(self):
+        version = NvpApiClient.NVPVersion('2.0')
+        function = versioning.get_function_by_version(
+            routerlib.ROUTER_FUNC_DICT, 'create_lrouter', version)
+        self.assertEqual(routerlib.create_implicit_routing_lrouter,
+                         function)
+
+    def test_function_handling_with_both_major_and_minor(self):
+        version = NvpApiClient.NVPVersion('3.2')
+        function = versioning.get_function_by_version(
+            routerlib.ROUTER_FUNC_DICT, 'create_lrouter', version)
+        self.assertEqual(routerlib.create_explicit_routing_lrouter,
+                         function)
+
+    def test_function_handling_with_newer_major(self):
+        version = NvpApiClient.NVPVersion('5.2')
+        function = versioning.get_function_by_version(
+            routerlib.ROUTER_FUNC_DICT, 'create_lrouter', version)
+        self.assertEqual(routerlib.create_explicit_routing_lrouter,
+                         function)
+
+    def test_function_handling_with_obsolete_major(self):
+        version = NvpApiClient.NVPVersion('1.2')
+        self.assertRaises(NotImplementedError,
+                          versioning.get_function_by_version,
+                          routerlib.ROUTER_FUNC_DICT,
+                          'create_lrouter', version)
+
+    def test_function_handling_with_unknown_version(self):
+        self.assertRaises(NvpApiClient.ServiceUnavailable,
+                          versioning.get_function_by_version,
+                          routerlib.ROUTER_FUNC_DICT,
+                          'create_lrouter', None)
index bdb848dfa186a7008e86fe0987903de4e8a4cdca..de67969127b753b9d8fab74d44c5643c12143ab3 100644 (file)
@@ -638,7 +638,7 @@ class TestNiciraL3NatTestCase(NiciraL3NatTest,
         self._test_router_create_with_distributed(True, True)
 
     def test_router_create_distributed_with_new_nvp_versions(self):
-        with mock.patch.object(nvplib, 'create_explicit_route_lrouter'):
+        with mock.patch.object(nsxlib.router, 'create_explicit_route_lrouter'):
             self._test_router_create_with_distributed(True, True, '3.2')
             self._test_router_create_with_distributed(True, True, '4.0')
             self._test_router_create_with_distributed(True, True, '4.1')
@@ -655,12 +655,13 @@ class TestNiciraL3NatTestCase(NiciraL3NatTest,
     def test_router_create_on_obsolete_platform(self):
 
         def obsolete_response(*args, **kwargs):
-            response = nvplib._create_implicit_routing_lrouter(*args, **kwargs)
+            response = (nsxlib.router.
+                        _create_implicit_routing_lrouter(*args, **kwargs))
             response.pop('distributed')
             return response
 
         with mock.patch.object(
-            nvplib, 'create_lrouter', new=obsolete_response):
+            nsxlib.router, 'create_lrouter', new=obsolete_response):
             self._test_router_create_with_distributed(None, False, '2.2')
 
     def _create_router_with_gw_info_for_test(self, subnet):
@@ -673,7 +674,7 @@ class TestNiciraL3NatTestCase(NiciraL3NatTest,
         return router_req.get_response(self.ext_api)
 
     def test_router_create_nvp_error_returns_500(self, vlan_id=None):
-        with mock.patch.object(nvplib,
+        with mock.patch.object(nsxlib.router,
                                'create_router_lport',
                                side_effect=NvpApiClient.NvpApiException):
             with self._create_l3_ext_network(vlan_id) as net:
@@ -1019,7 +1020,7 @@ class TestNiciraL3NatTestCase(NiciraL3NatTest,
         with self._create_l3_ext_network() as net:
             with self.subnet(network=net) as s:
                 with mock.patch.object(
-                    nvplib,
+                    nsxlib.router,
                     'do_request',
                     side_effect=nvp_exc.MaintenanceInProgress):
                     data = {'router': {'tenant_id': 'whatever'}}
index 9aad462daafb3e4246f3436aecb7b28b1644316f..6262fdc3d584e5be8ca03f3859ef645ae9d266df 100644 (file)
@@ -171,7 +171,8 @@ class NsxUtilsTestCase(base.BaseTestCase):
         # found for a given port identifier
         exp_lr_uuid = uuidutils.generate_uuid()
         self._mock_router_mapping_db_calls(None)
-        with mock.patch(nicira_method('query_lrouters'),
+        with mock.patch(nicira_method('query_lrouters',
+                                      module_name='nsxlib.router'),
                         return_value=[{'uuid': exp_lr_uuid}]):
             self._verify_get_nsx_router_id(exp_lr_uuid)
 
@@ -179,6 +180,7 @@ class NsxUtilsTestCase(base.BaseTestCase):
         # This test verifies that the function returns None if the mapping
         # are not found both in the db and in the backend
         self._mock_router_mapping_db_calls(None)
-        with mock.patch(nicira_method('query_lrouters'),
+        with mock.patch(nicira_method('query_lrouters',
+                                      module_name='nsxlib.router'),
                         return_value=[]):
             self._verify_get_nsx_router_id(None)
index 01e07f71a7732e7bcf37480af89011b4547bd5fe..740197d3d18b9087d8758c17ddd841119e166923 100644 (file)
@@ -22,7 +22,6 @@ import mock
 
 from neutron.common import constants
 from neutron.common import exceptions
-from neutron.openstack.common import uuidutils
 from neutron.plugins.nicira.common import config  # noqa
 from neutron.plugins.nicira.common import exceptions as nvp_exc
 from neutron.plugins.nicira.common import utils
@@ -31,7 +30,6 @@ from neutron.plugins.nicira import NvpApiClient
 from neutron.plugins.nicira import nvplib
 from neutron.tests import base
 from neutron.tests.unit.nicira import fake_nvpapiclient
-from neutron.tests.unit.nicira import nicira_method
 from neutron.tests.unit.nicira import NVPAPI_NAME
 from neutron.tests.unit.nicira import STUBS_PATH
 from neutron.tests.unit import test_api_v2
@@ -74,38 +72,7 @@ class NvplibTestCase(base.BaseTestCase):
         return dict((t['scope'], t['tag']) for t in tags)
 
 
-class TestNvplibNatRules(NvplibTestCase):
-
-    def _test_create_lrouter_dnat_rule(self, version):
-        with mock.patch.object(self.fake_cluster.api_client,
-                               'get_nvp_version',
-                               new=lambda: NvpApiClient.NVPVersion(version)):
-            tenant_id = 'pippo'
-            lrouter = nvplib.create_lrouter(self.fake_cluster,
-                                            uuidutils.generate_uuid(),
-                                            tenant_id,
-                                            'fake_router',
-                                            '192.168.0.1')
-            nat_rule = nvplib.create_lrouter_dnat_rule(
-                self.fake_cluster, lrouter['uuid'], '10.0.0.99',
-                match_criteria={'destination_ip_addresses':
-                                '192.168.0.5'})
-            uri = nvplib._build_uri_path(nvplib.LROUTERNAT_RESOURCE,
-                                         nat_rule['uuid'],
-                                         lrouter['uuid'])
-            resp_obj = nvplib.do_request("GET", uri, cluster=self.fake_cluster)
-            self.assertEqual('DestinationNatRule', resp_obj['type'])
-            self.assertEqual('192.168.0.5',
-                             resp_obj['match']['destination_ip_addresses'])
-
-    def test_create_lrouter_dnat_rule_v2(self):
-        self._test_create_lrouter_dnat_rule('2.9')
-
-    def test_create_lrouter_dnat_rule_v31(self):
-        self._test_create_lrouter_dnat_rule('3.1')
-
-
-class NvplibNegativeTests(base.BaseTestCase):
+class NsxlibNegativeBaseTestCase(base.BaseTestCase):
 
     def setUp(self):
         # mock nvp api client
@@ -132,10 +99,13 @@ class NvplibNegativeTests(base.BaseTestCase):
             self.fake_cluster.req_timeout, self.fake_cluster.http_timeout,
             self.fake_cluster.retries, self.fake_cluster.redirects)
 
-        super(NvplibNegativeTests, self).setUp()
+        super(NsxlibNegativeBaseTestCase, self).setUp()
         self.addCleanup(self.fc.reset_all)
         self.addCleanup(self.mock_nvpapi.stop)
 
+
+class L2GatewayNegativeTestCase(NsxlibNegativeBaseTestCase):
+
     def test_create_l2_gw_service_on_failure(self):
         self.assertRaises(nvplib.NvpApiClient.NvpApiException,
                           nvplib.create_l2_gw_service,
@@ -164,35 +134,6 @@ class NvplibNegativeTests(base.BaseTestCase):
                           'fake-gateway',
                           'pluto')
 
-    def test_create_lrouter_on_failure(self):
-        self.assertRaises(nvplib.NvpApiClient.NvpApiException,
-                          nvplib.create_lrouter,
-                          self.fake_cluster,
-                          uuidutils.generate_uuid(),
-                          'pluto',
-                          'fake_router',
-                          'my_hop')
-
-    def test_delete_lrouter_on_failure(self):
-        self.assertRaises(nvplib.NvpApiClient.NvpApiException,
-                          nvplib.delete_lrouter,
-                          self.fake_cluster,
-                          'fake_router')
-
-    def test_get_lrouter_on_failure(self):
-        self.assertRaises(nvplib.NvpApiClient.NvpApiException,
-                          nvplib.get_lrouter,
-                          self.fake_cluster,
-                          'fake_router')
-
-    def test_update_lrouter_on_failure(self):
-        self.assertRaises(nvplib.NvpApiClient.NvpApiException,
-                          nvplib.update_lrouter,
-                          self.fake_cluster,
-                          'fake_router',
-                          'pluto',
-                          'new_hop')
-
 
 class TestNvplibL2Gateway(NvplibTestCase):
 
@@ -404,824 +345,6 @@ class TestNvplibLogicalSwitches(NvplibTestCase):
                           self.fake_cluster, 'whatever', ['whatever'])
 
 
-class TestNvplibExplicitLRouters(NvplibTestCase):
-
-    def setUp(self):
-        self.fake_version = '3.2'
-        super(TestNvplibExplicitLRouters, self).setUp()
-
-    def _get_lrouter(self, tenant_id, router_name, router_id, relations=None):
-        schema = '/ws.v1/schema/RoutingTableRoutingConfig'
-
-        router = {'display_name': router_name,
-                  'uuid': router_id,
-                  'tags': [{'scope': 'quantum', 'tag': nvplib.NEUTRON_VERSION},
-                           {'scope': 'os_tid', 'tag': '%s' % tenant_id}],
-                  'distributed': False,
-                  'routing_config': {'type': 'RoutingTableRoutingConfig',
-                                     '_schema': schema},
-                  '_schema': schema,
-                  'nat_synchronization_enabled': True,
-                  'replication_mode': 'service',
-                  'type': 'LogicalRouterConfig',
-                  '_href': '/ws.v1/lrouter/%s' % router_id, }
-        if relations:
-            router['_relations'] = relations
-        return router
-
-    def _get_single_route(self, router_id, route_id='fake_route_id_0',
-                          prefix='0.0.0.0/0', next_hop_ip='1.1.1.1'):
-        return {'protocol': 'static',
-                '_href': '/ws.v1/lrouter/%s/rib/%s' % (router_id, route_id),
-                'prefix': prefix,
-                '_schema': '/ws.v1/schema/RoutingTableEntry',
-                'next_hop_ip': next_hop_ip,
-                'action': 'accept',
-                'uuid': route_id}
-
-    def test_prepare_body_with_implicit_routing_config(self):
-        router_name = 'fake_router_name'
-        tenant_id = 'fake_tenant_id'
-        neutron_router_id = 'pipita_higuain'
-        router_type = 'SingleDefaultRouteImplicitRoutingConfig'
-        route_config = {
-            'default_route_next_hop': {'gateway_ip_address': 'fake_address',
-                                       'type': 'RouterNextHop'}, }
-        body = nvplib._prepare_lrouter_body(router_name, neutron_router_id,
-                                            tenant_id, router_type,
-                                            **route_config)
-        expected = {'display_name': 'fake_router_name',
-                    'routing_config': {
-                        'default_route_next_hop':
-                        {'gateway_ip_address': 'fake_address',
-                         'type': 'RouterNextHop'},
-                        'type': 'SingleDefaultRouteImplicitRoutingConfig'},
-                    'tags': [{'scope': 'os_tid', 'tag': 'fake_tenant_id'},
-                             {'scope': 'q_router_id', 'tag': 'pipita_higuain'},
-                             {'scope': 'quantum',
-                              'tag': nvplib.NEUTRON_VERSION}],
-                    'type': 'LogicalRouterConfig'}
-        self.assertEqual(expected, body)
-
-    def test_prepare_body_without_routing_config(self):
-        router_name = 'fake_router_name'
-        tenant_id = 'fake_tenant_id'
-        router_type = 'RoutingTableRoutingConfig'
-        neutron_router_id = 'marekiaro_hamsik'
-        body = nvplib._prepare_lrouter_body(router_name, neutron_router_id,
-                                            tenant_id, router_type)
-        expected = {'display_name': 'fake_router_name',
-                    'routing_config': {'type': 'RoutingTableRoutingConfig'},
-                    'tags': [{'scope': 'os_tid', 'tag': 'fake_tenant_id'},
-                             {'scope': 'q_router_id',
-                              'tag': 'marekiaro_hamsik'},
-                             {'scope': 'quantum',
-                              'tag': nvplib.NEUTRON_VERSION}],
-                    'type': 'LogicalRouterConfig'}
-        self.assertEqual(expected, body)
-
-    def test_get_lrouter(self):
-        tenant_id = 'fake_tenant_id'
-        router_name = 'fake_router_name'
-        router_id = 'fake_router_id'
-        relations = {
-            'LogicalRouterStatus':
-            {'_href': '/ws.v1/lrouter/%s/status' % router_id,
-             'lport_admin_up_count': 1,
-             '_schema': '/ws.v1/schema/LogicalRouterStatus',
-             'lport_count': 1,
-             'fabric_status': True,
-             'type': 'LogicalRouterStatus',
-             'lport_link_up_count': 0, }, }
-
-        with mock.patch(nicira_method('do_request'),
-                        return_value=self._get_lrouter(tenant_id,
-                                                       router_name,
-                                                       router_id,
-                                                       relations)):
-            lrouter = nvplib.get_lrouter(self.fake_cluster, router_id)
-            self.assertTrue(
-                lrouter['_relations']['LogicalRouterStatus']['fabric_status'])
-
-    def test_create_lrouter(self):
-        tenant_id = 'fake_tenant_id'
-        router_name = 'fake_router_name'
-        router_id = 'fake_router_id'
-        nexthop_ip = '10.0.0.1'
-        with mock.patch(nicira_method('do_request'),
-                        return_value=self._get_lrouter(tenant_id,
-                                                       router_name,
-                                                       router_id)):
-            lrouter = nvplib.create_lrouter(self.fake_cluster,
-                                            uuidutils.generate_uuid(),
-                                            tenant_id,
-                                            router_name, nexthop_ip)
-            self.assertEqual(lrouter['routing_config']['type'],
-                             'RoutingTableRoutingConfig')
-            self.assertNotIn('default_route_next_hop',
-                             lrouter['routing_config'])
-
-    def test_update_lrouter_nvp_with_no_routes(self):
-        router_id = 'fake_router_id'
-        new_routes = [{"nexthop": "10.0.0.2",
-                       "destination": "169.254.169.0/30"}, ]
-
-        nvp_routes = [self._get_single_route(router_id)]
-        with mock.patch(nicira_method('get_explicit_routes_lrouter'),
-                        return_value=nvp_routes):
-            with mock.patch(nicira_method('create_explicit_route_lrouter'),
-                            return_value='fake_uuid'):
-                old_routes = nvplib.update_explicit_routes_lrouter(
-                    self.fake_cluster, router_id, new_routes)
-        self.assertEqual(old_routes, nvp_routes)
-
-    def test_update_lrouter_nvp_with_no_routes_raise_nvp_exception(self):
-        router_id = 'fake_router_id'
-        new_routes = [{"nexthop": "10.0.0.2",
-                       "destination": "169.254.169.0/30"}, ]
-
-        nvp_routes = [self._get_single_route(router_id)]
-        with mock.patch(nicira_method('get_explicit_routes_lrouter'),
-                        return_value=nvp_routes):
-            with mock.patch(nicira_method('create_explicit_route_lrouter'),
-                            side_effect=NvpApiClient.NvpApiException):
-                self.assertRaises(NvpApiClient.NvpApiException,
-                                  nvplib.update_explicit_routes_lrouter,
-                                  self.fake_cluster, router_id, new_routes)
-
-    def test_update_lrouter_with_routes(self):
-        router_id = 'fake_router_id'
-        new_routes = [{"next_hop_ip": "10.0.0.2",
-                       "prefix": "169.254.169.0/30"}, ]
-
-        nvp_routes = [self._get_single_route(router_id),
-                      self._get_single_route(router_id, 'fake_route_id_1',
-                                             '0.0.0.1/24', '10.0.0.3'),
-                      self._get_single_route(router_id, 'fake_route_id_2',
-                                             '0.0.0.2/24', '10.0.0.4'), ]
-
-        with mock.patch(nicira_method('get_explicit_routes_lrouter'),
-                        return_value=nvp_routes):
-            with mock.patch(nicira_method('delete_explicit_route_lrouter'),
-                            return_value=None):
-                with mock.patch(nicira_method(
-                    'create_explicit_route_lrouter'),
-                    return_value='fake_uuid'):
-                    old_routes = nvplib.update_explicit_routes_lrouter(
-                        self.fake_cluster, router_id, new_routes)
-        self.assertEqual(old_routes, nvp_routes)
-
-    def test_update_lrouter_with_routes_raises_nvp_expception(self):
-        router_id = 'fake_router_id'
-        new_routes = [{"nexthop": "10.0.0.2",
-                       "destination": "169.254.169.0/30"}, ]
-
-        nvp_routes = [self._get_single_route(router_id),
-                      self._get_single_route(router_id, 'fake_route_id_1',
-                                             '0.0.0.1/24', '10.0.0.3'),
-                      self._get_single_route(router_id, 'fake_route_id_2',
-                                             '0.0.0.2/24', '10.0.0.4'), ]
-
-        with mock.patch(nicira_method('get_explicit_routes_lrouter'),
-                        return_value=nvp_routes):
-            with mock.patch(nicira_method('delete_explicit_route_lrouter'),
-                            side_effect=NvpApiClient.NvpApiException):
-                with mock.patch(
-                    nicira_method('create_explicit_route_lrouter'),
-                    return_value='fake_uuid'):
-                    self.assertRaises(
-                        NvpApiClient.NvpApiException,
-                        nvplib.update_explicit_routes_lrouter,
-                        self.fake_cluster, router_id, new_routes)
-
-
-class TestNvplibLogicalRouters(NvplibTestCase):
-
-    def _verify_lrouter(self, res_lrouter,
-                        expected_uuid,
-                        expected_display_name,
-                        expected_nexthop,
-                        expected_tenant_id,
-                        expected_neutron_id=None,
-                        expected_distributed=None):
-        self.assertEqual(res_lrouter['uuid'], expected_uuid)
-        nexthop = (res_lrouter['routing_config']
-                   ['default_route_next_hop']['gateway_ip_address'])
-        self.assertEqual(nexthop, expected_nexthop)
-        router_tags = self._build_tag_dict(res_lrouter['tags'])
-        self.assertIn('os_tid', router_tags)
-        self.assertEqual(res_lrouter['display_name'], expected_display_name)
-        self.assertEqual(expected_tenant_id, router_tags['os_tid'])
-        if expected_distributed is not None:
-            self.assertEqual(expected_distributed,
-                             res_lrouter['distributed'])
-        if expected_neutron_id:
-            self.assertIn('q_router_id', router_tags)
-            self.assertEqual(expected_neutron_id, router_tags['q_router_id'])
-
-    def test_get_lrouters(self):
-        lrouter_uuids = [nvplib.create_lrouter(
-            self.fake_cluster, 'whatever', 'pippo', 'fake-lrouter-%s' % k,
-            '10.0.0.1')['uuid'] for k in range(3)]
-        routers = nvplib.get_lrouters(self.fake_cluster, 'pippo')
-        for router in routers:
-            self.assertIn(router['uuid'], lrouter_uuids)
-
-    def _create_lrouter(self, version, neutron_id=None, distributed=None):
-        with mock.patch.object(
-            self.fake_cluster.api_client, 'get_nvp_version',
-            return_value=NvpApiClient.NVPVersion(version)):
-                if not neutron_id:
-                    neutron_id = uuidutils.generate_uuid()
-                lrouter = nvplib.create_lrouter(
-                    self.fake_cluster, neutron_id, 'pippo',
-                    'fake-lrouter', '10.0.0.1', distributed=distributed)
-                return nvplib.get_lrouter(self.fake_cluster,
-                                          lrouter['uuid'])
-
-    def test_create_and_get_lrouter_v30(self):
-        neutron_id = uuidutils.generate_uuid()
-        res_lrouter = self._create_lrouter('3.0', neutron_id=neutron_id)
-        self._verify_lrouter(res_lrouter, res_lrouter['uuid'],
-                             'fake-lrouter', '10.0.0.1', 'pippo',
-                             neutron_id)
-
-    def test_create_and_get_lrouter_v31_centralized(self):
-        neutron_id = uuidutils.generate_uuid()
-        res_lrouter = self._create_lrouter('3.1', neutron_id=neutron_id,
-                                           distributed=False)
-        self._verify_lrouter(res_lrouter, res_lrouter['uuid'],
-                             'fake-lrouter', '10.0.0.1', 'pippo',
-                             expected_neutron_id=neutron_id,
-                             expected_distributed=False)
-
-    def test_create_and_get_lrouter_v31_distributed(self):
-        neutron_id = uuidutils.generate_uuid()
-        res_lrouter = self._create_lrouter('3.1', neutron_id=neutron_id,
-                                           distributed=True)
-        self._verify_lrouter(res_lrouter, res_lrouter['uuid'],
-                             'fake-lrouter', '10.0.0.1', 'pippo',
-                             expected_neutron_id=neutron_id,
-                             expected_distributed=True)
-
-    def test_create_and_get_lrouter_name_exceeds_40chars(self):
-        neutron_id = uuidutils.generate_uuid()
-        display_name = '*' * 50
-        lrouter = nvplib.create_lrouter(self.fake_cluster,
-                                        neutron_id,
-                                        'pippo',
-                                        display_name,
-                                        '10.0.0.1')
-        res_lrouter = nvplib.get_lrouter(self.fake_cluster,
-                                         lrouter['uuid'])
-        self._verify_lrouter(res_lrouter, lrouter['uuid'],
-                             '*' * 40, '10.0.0.1', 'pippo',
-                             expected_neutron_id=neutron_id)
-
-    def _test_version_dependent_update_lrouter(self, version):
-        def foo(*args, **kwargs):
-            return version
-
-        foo_func_dict = {
-            'update_lrouter': {
-                2: {-1: foo},
-                3: {-1: foo, 2: foo}
-            }
-        }
-
-        with mock.patch.object(self.fake_cluster.api_client,
-                               'get_nvp_version',
-                               return_value=NvpApiClient.NVPVersion(version)):
-            with mock.patch.dict(nvplib.NVPLIB_FUNC_DICT,
-                                 foo_func_dict, clear=True):
-                return nvplib.update_lrouter(
-                    self.fake_cluster, 'foo_router_id', 'foo_router_name',
-                    'foo_nexthop', routes={'foo_destination': 'foo_address'})
-
-    def test_version_dependent_update_lrouter_old_versions(self):
-        self.assertRaises(nvp_exc.NvpInvalidVersion,
-                          self._test_version_dependent_update_lrouter,
-                          "2.9")
-        self.assertRaises(nvp_exc.NvpInvalidVersion,
-                          self._test_version_dependent_update_lrouter,
-                          "3.0")
-        self.assertRaises(nvp_exc.NvpInvalidVersion,
-                          self._test_version_dependent_update_lrouter,
-                          "3.1")
-
-    def test_version_dependent_update_lrouter_new_versions(self):
-        self.assertEqual("3.2",
-                         self._test_version_dependent_update_lrouter("3.2"))
-        self.assertEqual("4.0",
-                         self._test_version_dependent_update_lrouter("4.0"))
-        self.assertEqual("4.1",
-                         self._test_version_dependent_update_lrouter("4.1"))
-
-    def test_update_lrouter_no_nexthop(self):
-        neutron_id = uuidutils.generate_uuid()
-        lrouter = nvplib.create_lrouter(self.fake_cluster,
-                                        neutron_id,
-                                        'pippo',
-                                        'fake-lrouter',
-                                        '10.0.0.1')
-        lrouter = nvplib.update_lrouter(self.fake_cluster,
-                                        lrouter['uuid'],
-                                        'new_name',
-                                        None)
-        res_lrouter = nvplib.get_lrouter(self.fake_cluster,
-                                         lrouter['uuid'])
-        self._verify_lrouter(res_lrouter, lrouter['uuid'],
-                             'new_name', '10.0.0.1', 'pippo',
-                             expected_neutron_id=neutron_id)
-
-    def test_update_lrouter(self):
-        neutron_id = uuidutils.generate_uuid()
-        lrouter = nvplib.create_lrouter(self.fake_cluster,
-                                        neutron_id,
-                                        'pippo',
-                                        'fake-lrouter',
-                                        '10.0.0.1')
-        lrouter = nvplib.update_lrouter(self.fake_cluster,
-                                        lrouter['uuid'],
-                                        'new_name',
-                                        '192.168.0.1')
-        res_lrouter = nvplib.get_lrouter(self.fake_cluster,
-                                         lrouter['uuid'])
-        self._verify_lrouter(res_lrouter, lrouter['uuid'],
-                             'new_name', '192.168.0.1', 'pippo',
-                             expected_neutron_id=neutron_id)
-
-    def test_update_nonexistent_lrouter_raises(self):
-        self.assertRaises(exceptions.NotFound,
-                          nvplib.update_lrouter,
-                          self.fake_cluster,
-                          'whatever',
-                          'foo', '9.9.9.9')
-
-    def test_delete_lrouter(self):
-        lrouter = nvplib.create_lrouter(self.fake_cluster,
-                                        uuidutils.generate_uuid(),
-                                        'pippo',
-                                        'fake-lrouter',
-                                        '10.0.0.1')
-        nvplib.delete_lrouter(self.fake_cluster, lrouter['uuid'])
-        self.assertRaises(exceptions.NotFound,
-                          nvplib.get_lrouter,
-                          self.fake_cluster,
-                          lrouter['uuid'])
-
-    def test_query_lrouter_ports(self):
-        lrouter = nvplib.create_lrouter(self.fake_cluster,
-                                        uuidutils.generate_uuid(),
-                                        'pippo',
-                                        'fake-lrouter',
-                                        '10.0.0.1')
-        router_port_uuids = [nvplib.create_router_lport(
-            self.fake_cluster, lrouter['uuid'], 'pippo',
-            'qp_id_%s' % k, 'port-%s' % k, True,
-            ['192.168.0.%s' % k], '00:11:22:33:44:55')['uuid']
-            for k in range(3)]
-        ports = nvplib.query_lrouter_lports(self.fake_cluster, lrouter['uuid'])
-        self.assertEqual(len(ports), 3)
-        for res_port in ports:
-            self.assertIn(res_port['uuid'], router_port_uuids)
-
-    def test_query_lrouter_lports_nonexistent_lrouter_raises(self):
-        self.assertRaises(
-            exceptions.NotFound, nvplib.create_router_lport,
-            self.fake_cluster, 'booo', 'pippo', 'neutron_port_id',
-            'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
-
-    def test_create_and_get_lrouter_port(self):
-        lrouter = nvplib.create_lrouter(self.fake_cluster,
-                                        uuidutils.generate_uuid(),
-                                        'pippo',
-                                        'fake-lrouter',
-                                        '10.0.0.1')
-        nvplib.create_router_lport(
-            self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
-            'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
-        ports = nvplib.query_lrouter_lports(self.fake_cluster, lrouter['uuid'])
-        self.assertEqual(len(ports), 1)
-        res_port = ports[0]
-        port_tags = self._build_tag_dict(res_port['tags'])
-        self.assertEqual(['192.168.0.1'], res_port['ip_addresses'])
-        self.assertIn('os_tid', port_tags)
-        self.assertIn('q_port_id', port_tags)
-        self.assertEqual('pippo', port_tags['os_tid'])
-        self.assertEqual('neutron_port_id', port_tags['q_port_id'])
-
-    def test_create_lrouter_port_nonexistent_router_raises(self):
-        self.assertRaises(
-            exceptions.NotFound, nvplib.create_router_lport,
-            self.fake_cluster, 'booo', 'pippo', 'neutron_port_id',
-            'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
-
-    def test_update_lrouter_port(self):
-        lrouter = nvplib.create_lrouter(self.fake_cluster,
-                                        uuidutils.generate_uuid(),
-                                        'pippo',
-                                        'fake-lrouter',
-                                        '10.0.0.1')
-        lrouter_port = nvplib.create_router_lport(
-            self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
-            'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
-        nvplib.update_router_lport(
-            self.fake_cluster, lrouter['uuid'], lrouter_port['uuid'],
-            'pippo', 'another_port_id', 'name', False,
-            ['192.168.0.1', '10.10.10.254'])
-
-        ports = nvplib.query_lrouter_lports(self.fake_cluster, lrouter['uuid'])
-        self.assertEqual(len(ports), 1)
-        res_port = ports[0]
-        port_tags = self._build_tag_dict(res_port['tags'])
-        self.assertEqual(['192.168.0.1', '10.10.10.254'],
-                         res_port['ip_addresses'])
-        self.assertEqual('False', res_port['admin_status_enabled'])
-        self.assertIn('os_tid', port_tags)
-        self.assertIn('q_port_id', port_tags)
-        self.assertEqual('pippo', port_tags['os_tid'])
-        self.assertEqual('another_port_id', port_tags['q_port_id'])
-
-    def test_update_lrouter_port_nonexistent_router_raises(self):
-        self.assertRaises(
-            exceptions.NotFound, nvplib.update_router_lport,
-            self.fake_cluster, 'boo-router', 'boo-port', 'pippo',
-            'neutron_port_id', 'name', True, ['192.168.0.1'])
-
-    def test_update_lrouter_port_nonexistent_port_raises(self):
-        lrouter = nvplib.create_lrouter(self.fake_cluster,
-                                        uuidutils.generate_uuid(),
-                                        'pippo',
-                                        'fake-lrouter',
-                                        '10.0.0.1')
-        self.assertRaises(
-            exceptions.NotFound, nvplib.update_router_lport,
-            self.fake_cluster, lrouter['uuid'], 'boo-port', 'pippo',
-            'neutron_port_id', 'name', True, ['192.168.0.1'])
-
-    def test_delete_lrouter_port(self):
-        lrouter = nvplib.create_lrouter(self.fake_cluster,
-                                        uuidutils.generate_uuid(),
-                                        'pippo',
-                                        'fake-lrouter',
-                                        '10.0.0.1')
-        lrouter_port = nvplib.create_router_lport(
-            self.fake_cluster, lrouter['uuid'], 'pippo', 'x', 'y', True, [],
-            '00:11:22:33:44:55')
-        ports = nvplib.query_lrouter_lports(self.fake_cluster, lrouter['uuid'])
-        self.assertEqual(len(ports), 1)
-        nvplib.delete_router_lport(self.fake_cluster, lrouter['uuid'],
-                                   lrouter_port['uuid'])
-        ports = nvplib.query_lrouter_lports(self.fake_cluster, lrouter['uuid'])
-        self.assertFalse(len(ports))
-
-    def test_delete_lrouter_port_nonexistent_router_raises(self):
-        self.assertRaises(exceptions.NotFound,
-                          nvplib.delete_router_lport,
-                          self.fake_cluster, 'xyz', 'abc')
-
-    def test_delete_lrouter_port_nonexistent_port_raises(self):
-        lrouter = nvplib.create_lrouter(self.fake_cluster,
-                                        uuidutils.generate_uuid(),
-                                        'pippo',
-                                        'fake-lrouter',
-                                        '10.0.0.1')
-        self.assertRaises(exceptions.NotFound,
-                          nvplib.delete_router_lport,
-                          self.fake_cluster, lrouter['uuid'], 'abc')
-
-    def test_delete_peer_lrouter_port(self):
-        lrouter = nvplib.create_lrouter(self.fake_cluster,
-                                        uuidutils.generate_uuid(),
-                                        'pippo',
-                                        'fake-lrouter',
-                                        '10.0.0.1')
-        lrouter_port = nvplib.create_router_lport(
-            self.fake_cluster, lrouter['uuid'], 'pippo', 'x', 'y', True, [],
-            '00:11:22:33:44:55')
-
-        def fakegetport(*args, **kwargs):
-            return {'_relations': {'LogicalPortAttachment':
-                                   {'peer_port_uuid': lrouter_port['uuid']}}}
-        # mock get_port
-        with mock.patch.object(nvplib, 'get_port', new=fakegetport):
-            nvplib.delete_peer_router_lport(self.fake_cluster,
-                                            lrouter_port['uuid'],
-                                            'whatwever', 'whatever')
-
-    def test_update_lrouter_port_ips_add_only(self):
-        lrouter = nvplib.create_lrouter(self.fake_cluster,
-                                        uuidutils.generate_uuid(),
-                                        'pippo',
-                                        'fake-lrouter',
-                                        '10.0.0.1')
-        lrouter_port = nvplib.create_router_lport(
-            self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
-            'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
-        nvplib.update_lrouter_port_ips(
-            self.fake_cluster, lrouter['uuid'], lrouter_port['uuid'],
-            ['10.10.10.254'], [])
-        ports = nvplib.query_lrouter_lports(self.fake_cluster, lrouter['uuid'])
-        self.assertEqual(len(ports), 1)
-        res_port = ports[0]
-        self.assertEqual(['10.10.10.254', '192.168.0.1'],
-                         res_port['ip_addresses'])
-
-    def test_update_lrouter_port_ips_remove_only(self):
-        lrouter = nvplib.create_lrouter(self.fake_cluster,
-                                        uuidutils.generate_uuid(),
-                                        'pippo',
-                                        'fake-lrouter',
-                                        '10.0.0.1')
-        lrouter_port = nvplib.create_router_lport(
-            self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
-            'name', True, ['192.168.0.1', '10.10.10.254'],
-            '00:11:22:33:44:55')
-        nvplib.update_lrouter_port_ips(
-            self.fake_cluster, lrouter['uuid'], lrouter_port['uuid'],
-            [], ['10.10.10.254'])
-        ports = nvplib.query_lrouter_lports(self.fake_cluster, lrouter['uuid'])
-        self.assertEqual(len(ports), 1)
-        res_port = ports[0]
-        self.assertEqual(['192.168.0.1'], res_port['ip_addresses'])
-
-    def test_update_lrouter_port_ips_add_and_remove(self):
-        lrouter = nvplib.create_lrouter(self.fake_cluster,
-                                        uuidutils.generate_uuid(),
-                                        'pippo',
-                                        'fake-lrouter',
-                                        '10.0.0.1')
-        lrouter_port = nvplib.create_router_lport(
-            self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
-            'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
-        nvplib.update_lrouter_port_ips(
-            self.fake_cluster, lrouter['uuid'], lrouter_port['uuid'],
-            ['10.10.10.254'], ['192.168.0.1'])
-        ports = nvplib.query_lrouter_lports(self.fake_cluster, lrouter['uuid'])
-        self.assertEqual(len(ports), 1)
-        res_port = ports[0]
-        self.assertEqual(['10.10.10.254'], res_port['ip_addresses'])
-
-    def test_update_lrouter_port_ips_nonexistent_router_raises(self):
-        self.assertRaises(
-            nvp_exc.NvpPluginException, nvplib.update_lrouter_port_ips,
-            self.fake_cluster, 'boo-router', 'boo-port', [], [])
-
-    def test_update_lrouter_port_ips_nvp_exception_raises(self):
-        lrouter = nvplib.create_lrouter(self.fake_cluster,
-                                        uuidutils.generate_uuid(),
-                                        'pippo',
-                                        'fake-lrouter',
-                                        '10.0.0.1')
-        lrouter_port = nvplib.create_router_lport(
-            self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
-            'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
-
-        def raise_nvp_exc(*args, **kwargs):
-            raise NvpApiClient.NvpApiException()
-
-        with mock.patch.object(nvplib, 'do_request', new=raise_nvp_exc):
-            self.assertRaises(
-                nvp_exc.NvpPluginException, nvplib.update_lrouter_port_ips,
-                self.fake_cluster, lrouter['uuid'],
-                lrouter_port['uuid'], [], [])
-
-    def test_plug_lrouter_port_patch_attachment(self):
-        tenant_id = 'pippo'
-        transport_zones_config = [{'zone_uuid': _uuid(),
-                                   'transport_type': 'stt'}]
-        lswitch = nvplib.create_lswitch(self.fake_cluster,
-                                        _uuid(),
-                                        tenant_id, 'fake-switch',
-                                        transport_zones_config)
-        lport = nvplib.create_lport(self.fake_cluster, lswitch['uuid'],
-                                    tenant_id, 'xyz',
-                                    'name', 'device_id', True)
-        lrouter = nvplib.create_lrouter(self.fake_cluster,
-                                        uuidutils.generate_uuid(),
-                                        tenant_id,
-                                        'fake-lrouter',
-                                        '10.0.0.1')
-        lrouter_port = nvplib.create_router_lport(
-            self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
-            'name', True, ['192.168.0.1'], '00:11:22:33:44:55:66')
-        result = nvplib.plug_router_port_attachment(
-            self.fake_cluster, lrouter['uuid'],
-            lrouter_port['uuid'],
-            lport['uuid'], 'PatchAttachment')
-        self.assertEqual(lport['uuid'],
-                         result['LogicalPortAttachment']['peer_port_uuid'])
-
-    def test_plug_lrouter_port_l3_gw_attachment(self):
-        lrouter = nvplib.create_lrouter(self.fake_cluster,
-                                        uuidutils.generate_uuid(),
-                                        'pippo',
-                                        'fake-lrouter',
-                                        '10.0.0.1')
-        lrouter_port = nvplib.create_router_lport(
-            self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
-            'name', True, ['192.168.0.1'], '00:11:22:33:44:55:66')
-        result = nvplib.plug_router_port_attachment(
-            self.fake_cluster, lrouter['uuid'],
-            lrouter_port['uuid'],
-            'gw_att', 'L3GatewayAttachment')
-        self.assertEqual(
-            'gw_att',
-            result['LogicalPortAttachment']['l3_gateway_service_uuid'])
-
-    def test_plug_lrouter_port_l3_gw_attachment_with_vlan(self):
-        lrouter = nvplib.create_lrouter(self.fake_cluster,
-                                        uuidutils.generate_uuid(),
-                                        'pippo',
-                                        'fake-lrouter',
-                                        '10.0.0.1')
-        lrouter_port = nvplib.create_router_lport(
-            self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
-            'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
-        result = nvplib.plug_router_port_attachment(
-            self.fake_cluster, lrouter['uuid'],
-            lrouter_port['uuid'],
-            'gw_att', 'L3GatewayAttachment', 123)
-        self.assertEqual(
-            'gw_att',
-            result['LogicalPortAttachment']['l3_gateway_service_uuid'])
-        self.assertEqual(
-            '123',
-            result['LogicalPortAttachment']['vlan_id'])
-
-    def test_plug_lrouter_port_invalid_attachment_type_raises(self):
-        lrouter = nvplib.create_lrouter(self.fake_cluster,
-                                        uuidutils.generate_uuid(),
-                                        'pippo',
-                                        'fake-lrouter',
-                                        '10.0.0.1')
-        lrouter_port = nvplib.create_router_lport(
-            self.fake_cluster, lrouter['uuid'], 'pippo', 'neutron_port_id',
-            'name', True, ['192.168.0.1'], '00:11:22:33:44:55')
-        self.assertRaises(nvp_exc.NvpInvalidAttachmentType,
-                          nvplib.plug_router_port_attachment,
-                          self.fake_cluster, lrouter['uuid'],
-                          lrouter_port['uuid'], 'gw_att', 'BadType')
-
-    def _test_create_router_snat_rule(self, version):
-        lrouter = nvplib.create_lrouter(self.fake_cluster,
-                                        uuidutils.generate_uuid(),
-                                        'pippo',
-                                        'fake-lrouter',
-                                        '10.0.0.1')
-        with mock.patch.object(self.fake_cluster.api_client,
-                               'get_nvp_version',
-                               new=lambda: NvpApiClient.NVPVersion(version)):
-            nvplib.create_lrouter_snat_rule(
-                self.fake_cluster, lrouter['uuid'],
-                '10.0.0.2', '10.0.0.2', order=200,
-                match_criteria={'source_ip_addresses': '192.168.0.24'})
-            rules = nvplib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
-            self.assertEqual(len(rules), 1)
-
-    def test_create_router_snat_rule_v3(self):
-        self._test_create_router_snat_rule('3.0')
-
-    def test_create_router_snat_rule_v2(self):
-        self._test_create_router_snat_rule('2.0')
-
-    def _test_create_router_dnat_rule(self, version, dest_port=None):
-        lrouter = nvplib.create_lrouter(self.fake_cluster,
-                                        uuidutils.generate_uuid(),
-                                        'pippo',
-                                        'fake-lrouter',
-                                        '10.0.0.1')
-        with mock.patch.object(self.fake_cluster.api_client,
-                               'get_nvp_version',
-                               return_value=NvpApiClient.NVPVersion(version)):
-            nvplib.create_lrouter_dnat_rule(
-                self.fake_cluster, lrouter['uuid'], '192.168.0.2', order=200,
-                dest_port=dest_port,
-                match_criteria={'destination_ip_addresses': '10.0.0.3'})
-            rules = nvplib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
-            self.assertEqual(len(rules), 1)
-
-    def test_create_router_dnat_rule_v3(self):
-        self._test_create_router_dnat_rule('3.0')
-
-    def test_create_router_dnat_rule_v2(self):
-        self._test_create_router_dnat_rule('2.0')
-
-    def test_create_router_dnat_rule_v2_with_destination_port(self):
-        self._test_create_router_dnat_rule('2.0', 8080)
-
-    def test_create_router_dnat_rule_v3_with_destination_port(self):
-        self._test_create_router_dnat_rule('3.0', 8080)
-
-    def test_create_router_snat_rule_invalid_match_keys_raises(self):
-        # In this case the version does not make a difference
-        lrouter = nvplib.create_lrouter(self.fake_cluster,
-                                        uuidutils.generate_uuid(),
-                                        'pippo',
-                                        'fake-lrouter',
-                                        '10.0.0.1')
-
-        with mock.patch.object(self.fake_cluster.api_client,
-                               'get_nvp_version',
-                               new=lambda: '2.0'):
-            self.assertRaises(AttributeError,
-                              nvplib.create_lrouter_snat_rule,
-                              self.fake_cluster, lrouter['uuid'],
-                              '10.0.0.2', '10.0.0.2', order=200,
-                              match_criteria={'foo': 'bar'})
-
-    def _test_create_router_nosnat_rule(self, version, expected=1):
-        lrouter = nvplib.create_lrouter(self.fake_cluster,
-                                        uuidutils.generate_uuid(),
-                                        'pippo',
-                                        'fake-lrouter',
-                                        '10.0.0.1')
-        with mock.patch.object(self.fake_cluster.api_client,
-                               'get_nvp_version',
-                               new=lambda: NvpApiClient.NVPVersion(version)):
-            nvplib.create_lrouter_nosnat_rule(
-                self.fake_cluster, lrouter['uuid'],
-                order=100,
-                match_criteria={'destination_ip_addresses': '192.168.0.0/24'})
-            rules = nvplib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
-            # NoSNAT rules do not exist in V2
-            self.assertEqual(len(rules), expected)
-
-    def test_create_router_nosnat_rule_v2(self):
-        self._test_create_router_nosnat_rule('2.0', expected=0)
-
-    def test_create_router_nosnat_rule_v3(self):
-        self._test_create_router_nosnat_rule('3.0')
-
-    def _prepare_nat_rules_for_delete_tests(self):
-        lrouter = nvplib.create_lrouter(self.fake_cluster,
-                                        uuidutils.generate_uuid(),
-                                        'pippo',
-                                        'fake-lrouter',
-                                        '10.0.0.1')
-        # v2 or v3 makes no difference for this test
-        with mock.patch.object(self.fake_cluster.api_client,
-                               'get_nvp_version',
-                               new=lambda: NvpApiClient.NVPVersion('2.0')):
-            nvplib.create_lrouter_snat_rule(
-                self.fake_cluster, lrouter['uuid'],
-                '10.0.0.2', '10.0.0.2', order=220,
-                match_criteria={'source_ip_addresses': '192.168.0.0/24'})
-            nvplib.create_lrouter_snat_rule(
-                self.fake_cluster, lrouter['uuid'],
-                '10.0.0.3', '10.0.0.3', order=200,
-                match_criteria={'source_ip_addresses': '192.168.0.2/32'})
-            nvplib.create_lrouter_dnat_rule(
-                self.fake_cluster, lrouter['uuid'], '192.168.0.2', order=200,
-                match_criteria={'destination_ip_addresses': '10.0.0.3'})
-        return lrouter
-
-    def test_delete_router_nat_rules_by_match_on_destination_ip(self):
-        lrouter = self._prepare_nat_rules_for_delete_tests()
-        rules = nvplib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
-        self.assertEqual(len(rules), 3)
-        nvplib.delete_nat_rules_by_match(
-            self.fake_cluster, lrouter['uuid'], 'DestinationNatRule', 1, 1,
-            destination_ip_addresses='10.0.0.3')
-        rules = nvplib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
-        self.assertEqual(len(rules), 2)
-
-    def test_delete_router_nat_rules_by_match_on_source_ip(self):
-        lrouter = self._prepare_nat_rules_for_delete_tests()
-        rules = nvplib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
-        self.assertEqual(len(rules), 3)
-        nvplib.delete_nat_rules_by_match(
-            self.fake_cluster, lrouter['uuid'], 'SourceNatRule', 1, 1,
-            source_ip_addresses='192.168.0.2/32')
-        rules = nvplib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
-        self.assertEqual(len(rules), 2)
-
-    def test_delete_router_nat_rules_by_match_no_match_expected(self):
-        lrouter = self._prepare_nat_rules_for_delete_tests()
-        rules = nvplib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
-        self.assertEqual(len(rules), 3)
-        nvplib.delete_nat_rules_by_match(
-            self.fake_cluster, lrouter['uuid'], 'SomeWeirdType', 0)
-        rules = nvplib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
-        self.assertEqual(len(rules), 3)
-        nvplib.delete_nat_rules_by_match(
-            self.fake_cluster, lrouter['uuid'], 'DestinationNatRule', 0,
-            destination_ip_addresses='99.99.99.99')
-        rules = nvplib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
-        self.assertEqual(len(rules), 3)
-
-    def test_delete_router_nat_rules_by_match_no_match_raises(self):
-        lrouter = self._prepare_nat_rules_for_delete_tests()
-        rules = nvplib.query_nat_rules(self.fake_cluster, lrouter['uuid'])
-        self.assertEqual(len(rules), 3)
-        self.assertRaises(
-            nvp_exc.NvpNatRuleMismatch,
-            nvplib.delete_nat_rules_by_match,
-            self.fake_cluster, lrouter['uuid'],
-            'SomeWeirdType', 1, 1)
-
-
 class TestNvplibSecurityProfile(NvplibTestCase):
 
     def test_create_and_get_security_profile(self):
@@ -1515,38 +638,6 @@ class TestNvplibClusterManagement(NvplibTestCase):
                           cluster=self.fake_cluster)
 
 
-class TestNvplibVersioning(base.BaseTestCase):
-
-    def test_function_handling_missing_minor(self):
-        version = NvpApiClient.NVPVersion('2.0')
-        function = nvplib.get_function_by_version('create_lrouter', version)
-        self.assertEqual(nvplib.create_implicit_routing_lrouter,
-                         function)
-
-    def test_function_handling_with_both_major_and_minor(self):
-        version = NvpApiClient.NVPVersion('3.2')
-        function = nvplib.get_function_by_version('create_lrouter', version)
-        self.assertEqual(nvplib.create_explicit_routing_lrouter,
-                         function)
-
-    def test_function_handling_with_newer_major(self):
-        version = NvpApiClient.NVPVersion('5.2')
-        function = nvplib.get_function_by_version('create_lrouter', version)
-        self.assertEqual(nvplib.create_explicit_routing_lrouter,
-                         function)
-
-    def test_function_handling_with_obsolete_major(self):
-        version = NvpApiClient.NVPVersion('1.2')
-        self.assertRaises(NotImplementedError,
-                          nvplib.get_function_by_version,
-                          'create_lrouter', version)
-
-    def test_function_handling_with_unknown_version(self):
-        self.assertRaises(NvpApiClient.ServiceUnavailable,
-                          nvplib.get_function_by_version,
-                          'create_lrouter', None)
-
-
 class NvplibMiscTestCase(base.BaseTestCase):
 
     def test_check_and_truncate_name_with_none(self):
@@ -1625,7 +716,3 @@ class NvplibMiscTestCase(base.BaseTestCase):
                     (nvplib.URI_PREFIX, parent_res,
                      par_id, child_res, res_id, 'doh'))
         self.assertEqual(expected, result)
-
-
-def _nicira_method(method_name, module_name='nvplib'):
-    return '%s.%s.%s' % ('neutron.plugins.nicira', module_name, method_name)