NSXv3: Router GW support

Change-Id: Ifae6815754f048cc1e8708662fa28e74ca297eeb
This commit is contained in:
linb 2015-08-06 09:20:26 +08:00
parent 43d2a57b82
commit 8d26063364
6 changed files with 460 additions and 49 deletions

View File

@ -16,6 +16,8 @@
from oslo_config import cfg
from oslo_log import log
from neutron.i18n import _LW
from vmware_nsx.neutron.plugins.vmware.common import exceptions as nsx_exc
from vmware_nsx.neutron.plugins.vmware.common import nsx_constants
from vmware_nsx.neutron.plugins.vmware.common import utils
@ -23,6 +25,16 @@ from vmware_nsx.neutron.plugins.vmware.nsxlib.v3 import client
LOG = log.getLogger(__name__)
# TODO(berlin): move them to nsx_constants file
# Router logical port types
LROUTERPORT_UPLINK = "LogicalRouterUplinkPort"
LROUTERPORT_DOWNLINK = "LogicalRouterDownLinkPort"
LROUTERPORT_LINK = "LogicalRouterLinkPort"
LROUTER_TYPES = [LROUTERPORT_UPLINK,
LROUTERPORT_DOWNLINK,
LROUTERPORT_LINK]
ROUTER_INTF_PORT_NAME = "Tier1-RouterDownLinkPort"
@ -39,6 +51,32 @@ def update_resource_with_retry(resource, payload):
return client.update_resource(resource, revised_payload)
def delete_resource_by_values(resource, res_id='id', skip_not_found=True,
**kwargs):
resources_get = client.get_resource(resource)
for res in resources_get['results']:
is_matched = True
for (key, value) in kwargs.items():
if res.get(key) != value:
is_matched = False
break
if is_matched:
LOG.debug("Deleting %s from resource %s", res, resource)
delete_resource = resource + "/" + str(res[res_id])
client.delete_resource(delete_resource)
return
if skip_not_found:
LOG.warning(_LW("No resource in %(res)s matched for values: "
"%(values)s"), {'res': resource,
'values': kwargs})
else:
err_msg = (_("No resource in %(res)s matched for values: %(values)s") %
{'res': resource,
'values': kwargs})
raise nsx_exc.ResourceNotFound(manager=client._get_manager_ip(),
operation=err_msg)
def create_logical_switch(display_name, transport_zone_id, tags,
replication_mode=nsx_constants.MTEP,
admin_state=True, vlan_id=None):
@ -181,6 +219,8 @@ def update_logical_router(lrouter_id, **kwargs):
def delete_logical_router(lrouter_id):
# TODO(berlin): need to verify whether cascade prefix is valid to delete
# router link port and its relative nat rules
resource = 'logical-routers/%s/' % lrouter_id
# TODO(salv-orlando): Must handle connection exceptions
@ -213,8 +253,8 @@ def create_logical_router_port_by_ls_id(logical_router_id,
except nsx_exc.ResourceNotFound:
return create_logical_router_port(logical_router_id,
ROUTER_INTF_PORT_NAME,
logical_switch_port_id,
resource_type,
logical_switch_port_id,
address_groups)
else:
return update_logical_router_port(port['id'], subnets=address_groups)
@ -222,15 +262,23 @@ def create_logical_router_port_by_ls_id(logical_router_id,
def create_logical_router_port(logical_router_id,
display_name,
logical_switch_port_id,
resource_type,
address_groups):
logical_port_id,
address_groups,
edge_cluster_member_index=None):
resource = 'logical-router-ports'
body = {'display_name': display_name,
'resource_type': resource_type,
'logical_router_id': logical_router_id,
'subnets': address_groups,
'linked_logical_switch_port_id': logical_switch_port_id}
'logical_router_id': logical_router_id}
if address_groups:
body['subnets'] = address_groups
if resource_type in [LROUTERPORT_UPLINK,
LROUTERPORT_DOWNLINK]:
body['linked_logical_switch_port_id'] = logical_port_id
elif logical_port_id:
body['linked_logical_router_port_id'] = logical_port_id
if edge_cluster_member_index:
body['edge_cluster_member_index'] = edge_cluster_member_index
return client.create_resource(resource, body)
@ -256,6 +304,56 @@ def delete_logical_router_port(logical_port_id):
client.delete_resource(resource)
def get_logical_router_ports_by_router_id(logical_router_id):
resource = 'logical-router-ports'
logical_router_ports = client.get_resource(
resource, logical_router_id=logical_router_id)
return logical_router_ports['results']
def get_tier1_logical_router_link_port(logical_router_id):
logical_router_ports = get_logical_router_ports_by_router_id(
logical_router_id)
for port in logical_router_ports:
if port['resource_type'] == LROUTERPORT_LINK:
return port
raise nsx_exc.ResourceNotFound(
manager=client._get_manager_ip(),
operation="get router link port")
def add_nat_rule(logical_router_id, action, translated_network,
source_net=None, dest_net=None,
enabled=True, rule_priority=None):
resource = 'logical-routers/%s/nat/rules' % logical_router_id
body = {'action': action,
'enabled': enabled,
'translated_network': translated_network}
if source_net:
body['match_source_network'] = source_net
if dest_net:
body['match_destination_network'] = dest_net
if rule_priority:
body['rule_priority'] = rule_priority
return client.create_resource(resource, body)
def delete_nat_rule(logical_router_id, nat_rule_id):
resource = 'logical-routers/%s/nat/rules/%s' % (logical_router_id,
nat_rule_id)
client.delete_resource(resource)
def delete_nat_rule_by_values(logical_router_id, **kwargs):
resource = 'logical-routers/%s/nat/rules' % logical_router_id
return delete_resource_by_values(resource, res_id='rule_id', **kwargs)
def update_logical_router_advertisement(logical_router_id, **kwargs):
resource = 'logical-routers/%s/routing/advertisement' % logical_router_id
return update_resource_with_retry(resource, kwargs)
def create_qos_switching_profile(tags, qos_marking=None, dscp=None, name=None,
description=None):
resource = 'switching-profiles'

View File

@ -65,13 +65,14 @@ def _validate_result(result, expected, operation):
raise manager_error(manager=manager_ip, operation=operation)
def get_resource(resource):
def get_resource(resource, **params):
manager, user, password, verify = _get_manager_endpoint()
url = manager + "/api/v1/%s" % resource
headers = {'Accept': 'application/json'}
result = requests.get(url, auth=auth.HTTPBasicAuth(user, password),
verify=verify, headers=headers,
cert=cfg.CONF.nsx_v3.ca_file)
cert=cfg.CONF.nsx_v3.ca_file,
params=params)
_validate_result(result, [requests.codes.ok],
_("reading resource: %s") % resource)
return result.json()

View File

@ -0,0 +1,128 @@
# Copyright 2015 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.
"""
NSX-V3 Plugin router module
"""
import random
from neutron.common import exceptions as n_exc
from neutron.i18n import _LW
from oslo_log import log
from vmware_nsx.neutron.plugins.vmware.common import exceptions as nsx_exc
from vmware_nsx.neutron.plugins.vmware.nsxlib import v3 as nsxlib
LOG = log.getLogger(__name__)
# TODO(berlin): Remove this when we merges the edge node auto
# placement feature.
MIN_EDGE_NODE_NUM = 1
TIER0_ROUTER_LINK_PORT_NAME = "TIER0-RouterLinkPort"
TIER1_ROUTER_LINK_PORT_NAME = "TIER1-RouterLinkPort"
def validate_tier0(tier0_groups_dict, tier0_uuid):
if tier0_uuid in tier0_groups_dict:
return
err_msg = None
try:
lrouter = nsxlib.get_logical_router(tier0_uuid)
except nsx_exc.ResourceNotFound:
err_msg = _("Failed to validate tier0 router %s since it is "
"not found at the backend") % tier0_uuid
else:
edge_cluster_uuid = lrouter.get('edge_cluster_id')
if not edge_cluster_uuid:
err_msg = _("Failed to get edge cluster uuid from tier0 "
"router %s at the backend") % lrouter
else:
edge_cluster = nsxlib.get_edge_cluster(edge_cluster_uuid)
member_index_list = [member['member_index']
for member in edge_cluster['members']]
if len(member_index_list) < MIN_EDGE_NODE_NUM:
err_msg = _("%(act_num)s edge members found in "
"edge_cluster %(cluster_id)s, however we "
"require at least %(exp_num)s edge nodes "
"in edge cluster for HA use.") % {
'act_num': len(member_index_list),
'exp_num': MIN_EDGE_NODE_NUM,
'cluster_id': edge_cluster_uuid}
if err_msg:
raise n_exc.InvalidInput(error_message=err_msg)
else:
tier0_groups_dict[tier0_uuid] = {
'edge_cluster_uuid': edge_cluster_uuid,
'member_index_list': member_index_list}
def add_router_link_port(tier1_uuid, tier0_uuid, edge_members):
# Create Tier0 logical router link port
tier0_link_port = nsxlib.create_logical_router_port(
tier0_uuid, display_name=TIER0_ROUTER_LINK_PORT_NAME,
resource_type=nsxlib.LROUTERPORT_LINK,
logical_port_id=None,
address_groups=None)
linked_logical_port_id = tier0_link_port['id']
edge_cluster_member_index = random.sample(
edge_members, MIN_EDGE_NODE_NUM)
# Create Tier1 logical router link port
nsxlib.create_logical_router_port(
tier1_uuid, display_name=TIER1_ROUTER_LINK_PORT_NAME,
resource_type=nsxlib.LROUTERPORT_LINK,
logical_port_id=linked_logical_port_id,
address_groups=None,
edge_cluster_member_index=edge_cluster_member_index)
def remove_router_link_port(tier1_uuid, tier0_uuid):
try:
tier1_link_port = nsxlib.get_tier1_logical_router_link_port(
tier1_uuid)
except nsx_exc.ResourceNotFound:
LOG.warning(_LW("Logical router link port for tier1 router: %s "
"not found at the backend"), tier1_uuid)
return
tier1_link_port_id = tier1_link_port['id']
tier0_link_port_id = tier1_link_port['linked_logical_router_port_id']
nsxlib.delete_logical_router_port(tier1_link_port_id)
nsxlib.delete_logical_router_port(tier0_link_port_id)
def update_advertisement(logical_router_id, advertise_route_nat,
advertise_route_connected):
return nsxlib.update_logical_router_advertisement(
logical_router_id,
advertise_nat_routes=advertise_route_nat,
advertise_connected_routes=advertise_route_connected)
def delete_gw_snat_rule(logical_router_id, gw_ip):
return nsxlib.delete_nat_rule_by_values(logical_router_id,
translated_network=gw_ip)
def add_gw_snat_rule(logical_router_id, gw_ip):
return nsxlib.add_nat_rule(logical_router_id, action="SNAT",
translated_network=gw_ip,
rule_priority=1000)
def update_router_edge_cluster(nsx_router_id, edge_cluster_uuid):
return nsxlib.update_logical_router(nsx_router_id,
edge_cluster_id=edge_cluster_uuid)

View File

@ -59,6 +59,7 @@ from vmware_nsx.neutron.plugins.vmware.common import utils
from vmware_nsx.neutron.plugins.vmware.dbexts import db as nsx_db
from vmware_nsx.neutron.plugins.vmware.nsxlib import v3 as nsxlib
from vmware_nsx.neutron.plugins.vmware.nsxlib.v3 import dfw_api as firewall
from vmware_nsx.neutron.plugins.vmware.nsxlib.v3 import router as routerlib
from vmware_nsx.neutron.plugins.vmware.nsxlib.v3 import security
LOG = log.getLogger(__name__)
@ -187,35 +188,11 @@ class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
return net_type, physical_net, vlan_id
def _validate_tier0(self, tier0_uuid):
if tier0_uuid in self.tier0_groups_dict:
return
err_msg = None
try:
lrouter = nsxlib.get_logical_router(tier0_uuid)
except nsx_exc.ResourceNotFound:
err_msg = _("Failed to validate tier0 router %s since it is "
"not found at the backend") % tier0_uuid
else:
edge_cluster_uuid = lrouter.get('edge_cluster_id')
if not edge_cluster_uuid:
err_msg = _("Failed to get edge cluster uuid from tier0 "
"router %s at the backend") % lrouter
else:
edge_cluster = nsxlib.get_edge_cluster(edge_cluster_uuid)
member_index_list = [member['member_index']
for member in edge_cluster['members']]
if not member_index_list:
err_msg = _("No edge members found in edge_cluster "
"%(cluster)s from tier0 router %(tier0)s") % {
'cluster': edge_cluster_uuid,
'tier0': tier0_uuid}
if err_msg:
raise n_exc.InvalidInput(error_message=err_msg)
else:
self.tier0_groups_dict[tier0_uuid] = {
'edge_cluster_uuid': edge_cluster_uuid,
'member_index_list': member_index_list}
def _get_edge_cluster_and_members(self, tier0_uuid):
routerlib.validate_tier0(self.tier0_groups_dict, tier0_uuid)
tier0_info = self.tier0_groups_dict[tier0_uuid]
return (tier0_info['edge_cluster_uuid'],
tier0_info['member_index_list'])
def _validate_external_net_create(self, net_data):
is_provider_net = False
@ -224,7 +201,7 @@ class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
else:
tier0_uuid = net_data[pnet.PHYSICAL_NETWORK]
is_provider_net = True
self._validate_tier0(tier0_uuid)
routerlib.validate_tier0(self.tier0_groups_dict, tier0_uuid)
return (is_provider_net, utils.NetworkTypes.L3_EXT, tier0_uuid, 0)
def _create_network_at_the_backend(self, context, net_data):
@ -559,6 +536,129 @@ class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
raise n_exc.BadRequest(resource='router', msg=msg)
return gw_info
def _get_external_attachment_info(self, context, router):
gw_port = router.gw_port
ipaddress = None
netmask = None
nexthop = None
if gw_port:
# gw_port may have multiple IPs, only configure the first one
if gw_port.get('fixed_ips'):
ipaddress = gw_port['fixed_ips'][0]['ip_address']
network_id = gw_port.get('network_id')
if network_id:
ext_net = self._get_network(context, network_id)
if not ext_net.external:
msg = (_("Network '%s' is not a valid external "
"network") % network_id)
raise n_exc.BadRequest(resource='router', msg=msg)
if ext_net.subnets:
ext_subnet = ext_net.subnets[0]
netmask = str(netaddr.IPNetwork(ext_subnet.cidr).netmask)
nexthop = ext_subnet.gateway_ip
return (ipaddress, netmask, nexthop)
def _get_tier0_uuid_by_net(self, context, network_id):
if not network_id:
return
network = self.get_network(context, network_id)
if not network.get(pnet.PHYSICAL_NETWORK):
return cfg.CONF.nsx_v3.default_tier0_router_uuid
else:
return network.get(pnet.PHYSICAL_NETWORK)
def _update_router_gw_info(self, context, router_id, info):
router = self._get_router(context, router_id)
org_ext_net_id = router.gw_port_id and router.gw_port.network_id
org_tier0_uuid = self._get_tier0_uuid_by_net(context, org_ext_net_id)
org_enable_snat = router.enable_snat
new_ext_net_id = info and info.get('network_id')
orgaddr, orgmask, _orgnexthop = (
self._get_external_attachment_info(
context, router))
# TODO(berlin): For nonat user case, we actually don't need a gw port
# which consumes one external ip. But after looking at the DB logic
# and we need to make a big change so don't touch it at present.
super(NsxV3Plugin, self)._update_router_gw_info(
context, router_id, info, router=router)
new_ext_net_id = router.gw_port_id and router.gw_port.network_id
new_tier0_uuid = self._get_tier0_uuid_by_net(context, new_ext_net_id)
new_enable_snat = router.enable_snat
newaddr, newmask, _newnexthop = (
self._get_external_attachment_info(
context, router))
nsx_router_id = nsx_db.get_nsx_router_id(context.session, router_id)
# Remove router link port between tier1 and tier0 if tier0 router link
# is removed or changed
remove_router_link_port = (org_tier0_uuid and
(not new_tier0_uuid or
org_tier0_uuid != new_tier0_uuid))
# Remove SNAT rules for gw ip if gw ip is deleted/changed or
# enable_snat is updated from True to False
remove_snat_rules = (org_enable_snat and orgaddr and
(newaddr != orgaddr or
not new_enable_snat))
# Revocate bgp announce for nonat subnets if tier0 router link is
# changed or enable_snat is updated from False to True
revocate_bgp_announce = (not org_enable_snat and org_tier0_uuid and
(new_tier0_uuid != org_tier0_uuid or
new_enable_snat))
# Add router link port between tier1 and tier0 if tier0 router link is
# added or changed to a new one
add_router_link_port = (new_tier0_uuid and
(not org_tier0_uuid or
org_tier0_uuid != new_tier0_uuid))
# Add SNAT rules for gw ip if gw ip is add/changed or
# enable_snat is updated from False to True
add_snat_rules = (new_enable_snat and newaddr and
(newaddr != orgaddr or
not org_enable_snat))
# Bgp announce for nonat subnets if tier0 router link is changed or
# enable_snat is updated from True to False
bgp_announce = (not new_enable_snat and new_tier0_uuid and
(new_tier0_uuid != org_tier0_uuid or
not org_enable_snat))
advertise_route_nat_flag = True if new_enable_snat else False
advertise_route_connected_flag = True if not new_enable_snat else False
if revocate_bgp_announce:
# TODO(berlin): revocate bgp announce on org tier0 router
pass
if remove_snat_rules:
routerlib.delete_gw_snat_rule(nsx_router_id, orgaddr)
if remove_router_link_port:
routerlib.remove_router_link_port(nsx_router_id, org_tier0_uuid)
if add_router_link_port:
# First update edge cluster info for router
edge_cluster_uuid, members = self._get_edge_cluster_and_members(
new_tier0_uuid)
routerlib.update_router_edge_cluster(
nsx_router_id, edge_cluster_uuid)
routerlib.add_router_link_port(nsx_router_id, new_tier0_uuid,
members)
if add_snat_rules:
routerlib.add_gw_snat_rule(nsx_router_id, newaddr)
if bgp_announce:
# TODO(berlin): bgp announce on new tier0 router
pass
if remove_snat_rules or add_snat_rules:
routerlib.update_advertisement(nsx_router_id,
advertise_route_nat_flag,
advertise_route_connected_flag)
def create_router(self, context, router):
# TODO(berlin): admin_state_up support
gw_info = self._extract_external_gw(context, router, is_extract=True)
@ -590,6 +690,9 @@ class NsxV3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
return self.get_router(context, router['id'])
def delete_router(self, context, router_id):
router = self.get_router(context, router_id)
if router.get(l3.EXTERNAL_GW_INFO):
self._update_router_gw_info(context, router_id, {})
nsx_router_id = nsx_db.get_nsx_router_id(context.session,
router_id)
ret_val = super(NsxV3Plugin, self).delete_router(context,

View File

@ -210,6 +210,7 @@ class NsxV3Mock(object):
self.logical_routers = {}
self.logical_router_ports = {}
self.logical_ports = {}
self.logical_router_nat_rules = {}
if default_tier0_router_uuid:
self.create_logical_router(
DEFAULT_TIER0_ROUTER_UUID, None,
@ -268,10 +269,11 @@ class NsxV3Mock(object):
def get_logical_router_port_by_ls_id(self, logical_switch_id):
router_ports = []
for router_port in self.logical_router_ports.values():
ls_port_id = router_port['linked_logical_switch_port_id']
port = self.get_logical_port(ls_port_id)
if port['logical_switch_id'] == logical_switch_id:
router_ports.append(router_port)
ls_port_id = router_port.get('linked_logical_switch_port_id')
if ls_port_id:
port = self.get_logical_port(ls_port_id)
if port['logical_switch_id'] == logical_switch_id:
router_ports.append(router_port)
if len(router_ports) >= 2:
raise nsx_exc.NsxPluginException(
err_msg=_("Can't support more than one logical router ports "
@ -305,18 +307,34 @@ class NsxV3Mock(object):
raise nsx_exc.ResourceNotFound(
manager=FAKE_MANAGER, operation="get_logical_port")
def get_logical_router_ports_by_router_id(self, logical_router_id):
logical_router_ports = []
for port_id in self.logical_router_ports.keys():
if (self.logical_router_ports[port_id]['logical_router_id'] ==
logical_router_id):
logical_router_ports.append(self.logical_router_ports[port_id])
return logical_router_ports
def create_logical_router_port(self, logical_router_id,
display_name,
logical_switch_port_id,
resource_type,
address_groups):
logical_port_id,
address_groups,
edge_cluster_member_index=None):
fake_router_port_uuid = uuidutils.generate_uuid()
body = {'id': fake_router_port_uuid,
'display_name': display_name,
body = {'display_name': display_name,
'resource_type': resource_type,
'logical_router_id': logical_router_id,
'subnets': address_groups,
'linked_logical_switch_port_id': logical_switch_port_id}
'logical_router_id': logical_router_id}
if address_groups:
body['subnets'] = address_groups
if resource_type in ["LogicalRouterUplinkPort",
"LogicalRouterDownLinkPort"]:
body['linked_logical_switch_port_id'] = logical_port_id
elif logical_port_id:
body['linked_logical_router_port_id'] = logical_port_id
if edge_cluster_member_index:
body['edge_cluster_member_index'] = edge_cluster_member_index
body['id'] = fake_router_port_uuid
self.logical_router_ports[fake_router_port_uuid] = body
return body
@ -335,3 +353,58 @@ class NsxV3Mock(object):
else:
raise nsx_exc.ResourceNotFound(
manager=FAKE_MANAGER, operation="update_logical_router_port")
def add_nat_rule(self, logical_router_id, action, translated_network,
source_net=None, dest_net=None, enabled=True,
rule_priority=None):
fake_rule_id = uuidutils.generate_uuid()
if logical_router_id not in self.logical_routers.keys():
raise nsx_exc.ResourceNotFound(
manager=FAKE_MANAGER, operation="get_logical_router")
body = {'action': action,
'enabled': enabled,
'translated_network': translated_network}
if source_net:
body['match_source_network'] = source_net
if dest_net:
body['match_destination_network'] = dest_net
if rule_priority:
body['rule_priority'] = rule_priority
body['rule_id'] = fake_rule_id
if self.logical_router_nat_rules.get(logical_router_id):
self.logical_router_nat_rules[logical_router_id][fake_rule_id] = (
body)
else:
self.logical_router_nat_rules[logical_router_id] = {
fake_rule_id: body}
return body
def delete_nat_rule(self, logical_router_id, nat_rule_id):
if (self.logical_router_nat_rules.get(logical_router_id) and
self.logical_router_nat_rules[logical_router_id].get(nat_rule_id)):
del self.logical_router_nat_rules[logical_router_id][nat_rule_id]
else:
raise nsx_exc.ResourceNotFound(
manager=FAKE_MANAGER, operation="delete_nat_rule")
def delete_nat_rule_by_values(self, logical_router_id, **kwargs):
if self.logical_router_nat_rules.get(logical_router_id):
nat_rules = self.logical_router_nat_rules[logical_router_id]
remove_nat_rule_ids = []
for nat_id, nat_body in nat_rules.items():
remove_flag = True
for k, v in kwargs.items():
if nat_body[k] != v:
remove_flag = False
break
if remove_flag:
remove_nat_rule_ids.append(nat_id)
for nat_id in remove_nat_rule_ids:
del nat_rules[nat_id]
else:
raise nsx_exc.ResourceNotFound(
manager=FAKE_MANAGER, operation="delete_nat_rule_by_values")
def update_logical_router_advertisement(self, logical_router_id, **kwargs):
# TODO(berlin): implement this latter.
pass

View File

@ -205,6 +205,14 @@ class L3NatTest(test_l3_plugin.L3BaseForIntTests, NsxPluginV3TestCase):
self.v3_mock.update_logical_router_port)
nsxlib.delete_logical_router_port = (
self.v3_mock.delete_logical_router_port)
nsxlib.add_nat_rule = self.v3_mock.add_nat_rule
nsxlib.delete_nat_rule = self.v3_mock.delete_nat_rule
nsxlib.delete_nat_rule_by_values = (
self.v3_mock.delete_nat_rule_by_values)
nsxlib.get_logical_router_ports_by_router_id = (
self.v3_mock.get_logical_router_ports_by_router_id)
nsxlib.update_logical_router_advertisement = (
self.v3_mock.update_logical_router_advertisement)
def _create_l3_ext_network(
self, physical_network=nsx_v3_mocks.DEFAULT_TIER0_ROUTER_UUID):