**** CubicPower OpenStack Study ****
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",
"replication_mode": cfg.CONF.NSX.replication_mode,
}
# 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
**** CubicPower OpenStack Study ****
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)
**** CubicPower OpenStack Study ****
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 NsxApiException: 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)
**** CubicPower OpenStack Study ****
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 NsxApiException: 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)
**** CubicPower OpenStack Study ****
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
**** CubicPower OpenStack Study ****
def delete_lrouter(cluster, lrouter_id):
do_request(HTTP_DELETE, _build_uri_path(LROUTER_RESOURCE,
resource_id=lrouter_id),
cluster=cluster)
**** CubicPower OpenStack Study ****
def get_lrouter(cluster, lrouter_id):
return do_request(HTTP_GET,
_build_uri_path(LROUTER_RESOURCE,
resource_id=lrouter_id,
relations='LogicalRouterStatus'),
cluster=cluster)
**** CubicPower OpenStack Study ****
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)
**** CubicPower OpenStack Study ****
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)
**** CubicPower OpenStack Study ****
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)
**** CubicPower OpenStack Study ****
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
**** CubicPower OpenStack Study ****
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)
**** CubicPower OpenStack Study ****
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
**** CubicPower OpenStack Study ****
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 api_exc.NsxApiException:
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
**** CubicPower OpenStack Study ****
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
**** CubicPower OpenStack Study ****
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
**** CubicPower OpenStack Study ****
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)
**** CubicPower OpenStack Study ****
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)
**** CubicPower OpenStack Study ****
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']
**** CubicPower OpenStack Study ****
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
**** CubicPower OpenStack Study ****
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
**** CubicPower OpenStack Study ****
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})
**** CubicPower OpenStack Study ****
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)
**** CubicPower OpenStack Study ****
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
**** CubicPower OpenStack Study ****
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 nsx_exc.InvalidAttachmentType(
attachment_type=nsx_attachment_type)
return do_request(
HTTP_PUT, uri, jsonutils.dumps(attach_obj), cluster=cluster)
**** CubicPower OpenStack Study ****
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
**** CubicPower OpenStack Study ****
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)
**** CubicPower OpenStack Study ****
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}
**** CubicPower OpenStack Study ****
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"))
**** CubicPower OpenStack Study ****
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"))
**** CubicPower OpenStack Study ****
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)
**** CubicPower OpenStack Study ****
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)
**** CubicPower OpenStack Study ****
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)
**** CubicPower OpenStack Study ****
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)
**** CubicPower OpenStack Study ****
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)
**** CubicPower OpenStack Study ****
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)
**** CubicPower OpenStack Study ****
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 nsx_exc.NatRuleMismatch(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)
**** CubicPower OpenStack Study ****
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)
**** CubicPower OpenStack Study ****
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
**** CubicPower OpenStack Study ****
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:
# 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 nsx_exc.NsxPluginException(err_msg=msg)
except api_exc.NsxApiException as e:
msg = _("An exception occurred while updating IP addresses on a "
"router logical port:%s") % str(e)
LOG.exception(msg)
raise nsx_exc.NsxPluginException(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)
**** CubicPower OpenStack Study ****
def create_lrouter(cluster, *args, **kwargs):
if kwargs.get('distributed', None):
v = cluster.api_client.get_version()
if (v.major, v.minor) < (3, 1):
raise nsx_exc.InvalidVersion(version=v)
return v
@versioned(ROUTER_FUNC_DICT)
**** CubicPower OpenStack Study ****
def get_default_route_explicit_routing_lrouter(cluster, *args, **kwargs):
pass
@versioned(ROUTER_FUNC_DICT)
**** CubicPower OpenStack Study ****
def update_lrouter(cluster, *args, **kwargs):
if kwargs.get('routes', None):
v = cluster.api_client.get_version()
if (v.major, v.minor) < (3, 2):
raise nsx_exc.InvalidVersion(version=v)
return v
@versioned(ROUTER_FUNC_DICT)
**** CubicPower OpenStack Study ****
def create_lrouter_dnat_rule(cluster, *args, **kwargs):
pass
@versioned(ROUTER_FUNC_DICT)
**** CubicPower OpenStack Study ****
def create_lrouter_snat_rule(cluster, *args, **kwargs):
pass
@versioned(ROUTER_FUNC_DICT)
**** CubicPower OpenStack Study ****
def create_lrouter_nosnat_rule(cluster, *args, **kwargs):
pass
@versioned(ROUTER_FUNC_DICT)
**** CubicPower OpenStack Study ****
def create_lrouter_nodnat_rule(cluster, *args, **kwargs):
pass