Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

create and delete snat for provider feature #1437

Open
wants to merge 1 commit into
base: 9.8-stable
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions etc/neutron/services/f5/f5-openstack-agent.ini
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,20 @@ f5_snat_mode = True
# f5_global_routed_mode = True.
#
f5_snat_addresses_per_subnet = 1

# f5_snat_per_provider set True to enable snat pool
# in Bigip for each neutron provider.
# f5_snat_per_provider set False to enable snat pool
# in Bigip for each neutron subnet.
f5_snat_per_provider = False

# f5_snat_addresses_per_provider set the number of
# members (IP address) in the snat pool for each provider,
# only when f5_snat_per_provider is enabled.
# This setting will be forced to 0 (zero) if
# f5_global_routed_mode = True.
f5_snat_addresses_per_provider = 1

#
# This setting will cause all networks to be
# defined under the common partition on the
Expand Down
12 changes: 11 additions & 1 deletion f5_openstack_agent/lbaasv2/drivers/bigip/agent_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,16 @@
default=True,
help=('use SNATs, not direct routed mode')
),
cfg.BoolOpt(
'f5_snat_per_provider',
default=False,
help=('use SNATs, not direct routed mode')
),
cfg.IntOpt(
'f5_snat_addresses_per_provider',
default=1,
help=('Interface and VLAN for the VTEP overlay network')
),
cfg.IntOpt(
'f5_snat_addresses_per_subnet',
default=1,
Expand Down Expand Up @@ -142,7 +152,7 @@
)
]

PERIODIC_TASK_INTERVAL = 10
PERIODIC_TASK_INTERVAL = 30


class LogicalServiceCache(object):
Expand Down
17 changes: 11 additions & 6 deletions f5_openstack_agent/lbaasv2/drivers/bigip/icontrol_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -499,21 +499,24 @@ def _init_bigip_managers(self):
self.tenant_manager = BigipTenantManager(self.conf, self)
self.cluster_manager = ClusterManager()
self.system_helper = SystemHelper()
self.lbaas_builder = LBaaSBuilder(self.conf, self)

# Set esd_processor object as soon as ServiceModelAdapter and
# LBaaSBuilder class instantiated, otherwise manager RPC exception
# will break setting esd_porcessor procedure.
self.init_esd()

if self.conf.f5_global_routed_mode:
self.network_builder = None
self.lbaas_builder = LBaaSBuilder(self.conf, self)
else:
self.network_builder = NetworkServiceBuilder(
self.conf.f5_global_routed_mode,
self.conf,
self,
self.l3_binding)
snat_manager = self.network_builder.bigip_snat_manager
self.lbaas_builder = LBaaSBuilder(self.conf, self,
snat_manager=snat_manager)

# Set esd_processor object as soon as ServiceModelAdapter and
# LBaaSBuilder class instantiated, otherwise manager RPC exception
# will break setting esd_porcessor procedure.
self.init_esd()

def _init_bigip_hostnames(self):
# Validate and parse bigip credentials
Expand Down Expand Up @@ -771,6 +774,7 @@ def _init_bigip(self, bigip, hostname, check_group_name=None):
self.system_helper.get_interface_macaddresses_dict(bigip)
bigip.assured_networks = {}
bigip.assured_tenant_snat_subnets = {}
bigip.assured_tenant_snat_providers = {}
bigip.assured_gateway_subnets = []

if self.conf.f5_ha_type != 'standalone':
Expand Down Expand Up @@ -1104,6 +1108,7 @@ def flush_cache(self):
for bigip in self.get_all_bigips():
bigip.assured_networks = {}
bigip.assured_tenant_snat_subnets = {}
bigip.assured_tenant_snat_providers = {}
bigip.assured_gateway_subnets = []

@serialized('get_all_deployed_loadbalancers')
Expand Down
50 changes: 48 additions & 2 deletions f5_openstack_agent/lbaasv2/drivers/bigip/lbaas_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,28 @@
from oslo_log import log as logging

from f5_openstack_agent.lbaasv2.drivers.bigip import constants_v2
from f5_openstack_agent.lbaasv2.drivers.bigip import exceptions as f5_ex
from f5_openstack_agent.lbaasv2.drivers.bigip import l7policy_service
from f5_openstack_agent.lbaasv2.drivers.bigip.lbaas_service import \
LbaasServiceObject
from f5_openstack_agent.lbaasv2.drivers.bigip import listener_service
from f5_openstack_agent.lbaasv2.drivers.bigip import pool_service
from f5_openstack_agent.lbaasv2.drivers.bigip import virtual_address

from requests import HTTPError

LOG = logging.getLogger(__name__)


class LBaaSBuilder(object):
# F5 LBaaS Driver using iControl for BIG-IP to
# create objects (vips, pools) - not using an iApp."""
# create objects (vips, pools) - not using an iApp.

def __init__(self, conf, driver, l2_service=None):
def __init__(self, conf, driver, l2_service=None, snat_manager=None):
self.conf = conf
self.driver = driver
self.l2_service = l2_service
self.bigip_snat_manager = snat_manager
self.service_adapter = driver.service_adapter
self.listener_builder = listener_service.ListenerServiceBuilder(
self.service_adapter,
Expand Down Expand Up @@ -182,6 +185,15 @@ def _assure_listeners_created(self, service):
for listener in listeners:
error = False
if self._is_not_pending_delete(listener):
# create and set snat for neutron provider here,
# since the neturon providers can be perceived
# in loadbalancer dict.
if (self.conf.f5_snat_mode and
self.conf.f5_snat_addresses_per_provider
and self.conf.f5_snat_addresses_per_provider > 0):
self._assure_provider_snats(bigips,
service,
loadbalancer)

svc = {"loadbalancer": loadbalancer,
"listener": listener,
Expand All @@ -204,6 +216,40 @@ def _assure_listeners_created(self, service):
if listener['admin_state_up']:
listener['operating_status'] = constants_v2.F5_ONLINE

def _assure_provider_snats(self, bigips, service, loadbalancer):
# snats_per_provider = self.conf.f5_snat_addresss_per_provider
snats_per_provider = self.conf.f5_snat_addresses_per_subnet
provider_name = loadbalancer["provider"]
lb_id = loadbalancer["id"]
tenant_id = loadbalancer["tenant_id"]
subnet_id = loadbalancer["vip_subnet_id"]
subnet = service["subnets"][subnet_id]
network_id = loadbalancer["network_id"]
network = service["networks"][network_id]

bigips = [bigip for bigip in bigips
if tenant_id not in bigip.assured_tenant_snat_providers or
subnet_id not in bigip.assured_tenant_snat_providers[
tenant_id] or provider_name not in
bigip.assured_tenant_snat_providers[tenant_id][subnet_id]]

if bigips and self.bigip_snat_manager:
snat_addrs = self.bigip_snat_manager.get_provider_snat_addrs(
provider_name, lb_id, tenant_id, subnet_id, snats_per_provider
)

if len(snat_addrs) != snats_per_provider:
raise f5_ex.SNATCreationException(
"Unable to satisfy request to allocate %d "
"snats. Actual SNAT count: %d SNATs" %
(snats_per_provider, len(snat_addrs)))

for bigip in bigips:
self.bigip_snat_manager.assure_provider_bigip_snats(
bigip, provider_name, snat_addrs, tenant_id, network,
subnet
)

def _assure_pools_created(self, service):
if "pools" not in service:
return
Expand Down
20 changes: 15 additions & 5 deletions f5_openstack_agent/lbaasv2/drivers/bigip/network_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def __init__(self, f5_global_routed_mode, conf, driver, l3_binding=None):

self.bigip_selfip_manager = BigipSelfIpManager(
self.driver, self.l2_service, self.driver.l3_binding)

self.bigip_snat_manager = BigipSnatManager(
self.driver, self.l2_service, self.driver.l3_binding)

Expand All @@ -55,7 +56,7 @@ def __init__(self, f5_global_routed_mode, conf, driver, l3_binding=None):
self.service_adapter = self.driver.service_adapter

def post_init(self):
# Run and Post Initialization Tasks """
# Run and Post Initialization Tasks
# run any post initialized tasks, now that the agent
# is fully connected
self.l2_service.post_init()
Expand All @@ -64,11 +65,11 @@ def tunnel_sync(self, tunnel_ips):
self.l2_service.tunnel_sync(tunnel_ips)

def set_tunnel_rpc(self, tunnel_rpc):
# Provide FDB Connector with ML2 RPC access """
# Provide FDB Connector with ML2 RPC access
self.l2_service.set_tunnel_rpc(tunnel_rpc)

def set_l2pop_rpc(self, l2pop_rpc):
# Provide FDB Connector with ML2 RPC access """
# Provide FDB Connector with ML2 RPC access
self.l2_service.set_l2pop_rpc(l2pop_rpc)

def initialize_vcmp(self):
Expand Down Expand Up @@ -207,7 +208,8 @@ def prep_service_networking(self, service, traffic_group):
LOG.debug("Getting subnetinfo for ...")
LOG.debug(assure_bigips)
for subnetinfo in subnetsinfo:
if self.conf.f5_snat_addresses_per_subnet > 0:
if (self.conf.f5_snat_addresses_per_subnet > 0 and
not self.conf.f5_snat_per_provider):
self._assure_subnet_snats(assure_bigips, service, subnetinfo)

if subnetinfo['is_for_member'] and not self.conf.f5_snat_mode:
Expand Down Expand Up @@ -602,6 +604,7 @@ def _assure_subnet_snats(self, assure_bigips, service, subnetinfo):
"Unable to satisfy request to allocate %d "
"snats. Actual SNAT count: %d SNATs" %
(snats_per_subnet, len(snat_addrs)))

for assure_bigip in assure_bigips:
self.bigip_snat_manager.assure_bigip_snats(
assure_bigip, subnetinfo, snat_addrs, tenant_id)
Expand Down Expand Up @@ -735,6 +738,7 @@ def update_bigip_l2(self, service):

def _assure_delete_nets_shared(self, bigip, service, subnet_hints):
# Assure shared configuration (which syncs) is deleted

deleted_names = set()
tenant_id = service['loadbalancer']['tenant_id']

Expand All @@ -746,6 +750,8 @@ def _assure_delete_nets_shared(self, bigip, service, subnet_hints):
if not self.conf.f5_snat_mode:
gw_name = delete_gateway(bigip, subnetinfo)
deleted_names.add(gw_name)
# if the a subnet has no related resource on the bigip,
# then the snat pool will be deleted
my_deleted_names, my_in_use_subnets = \
self.bigip_snat_manager.delete_bigip_snats(
bigip, subnetinfo, tenant_id)
Expand Down Expand Up @@ -863,6 +869,10 @@ def _get_subnets_to_delete(self, bigip, service, subnet_hints):

def _ips_exist_on_subnet(self, bigip, service, subnet, route_domain):
# Does the big-ip have any IP addresses on this subnet?
# if the loadbalancer is pending_delete status
# the F5 agent will check the subnet used by the loadbalancer for
# deleting. if any vip related or memeber ip within the subnet,
# then this function return False
LOG.debug("_ips_exist_on_subnet entry %s rd %s"
% (str(subnet['cidr']), route_domain))
route_domain = str(route_domain)
Expand Down Expand Up @@ -892,7 +902,7 @@ def _ips_exist_on_subnet(self, bigip, service, subnet, route_domain):
return True

# If there aren't any virtual addresses, are there
# node addresses on this subnet?
# node (member) addresses on this subnet?
nodes = self.network_helper.get_node_addresses(
bigip,
partition=folder
Expand Down
24 changes: 16 additions & 8 deletions f5_openstack_agent/lbaasv2/drivers/bigip/service_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,6 @@ def get_pool(self, service):
def snat_mode(self):
return self.conf.f5_snat_mode

def snat_count(self):
return self.conf.f5_snat_addresses_per_subnet

def vip_on_common_network(self, service):
loadbalancer = service.get('loadbalancer', {})
network_id = loadbalancer.get('network_id', "")
Expand Down Expand Up @@ -112,11 +109,22 @@ def get_virtual(self, service):
listener = service["listener"]
loadbalancer = service["loadbalancer"]

listener["use_snat"] = self.snat_mode() and not listener.get(
# set snat pool for listener
# when use transparent for CMCC, the use_snat must be True in
# in f5-openstack-agent.ini configuration file
listener["use_snat"] = self.conf.f5_snat_mode and not listener.get(
"transparent")
if listener["use_snat"] and self.snat_count() > 0:
listener["snat_pool_name"] = self.get_folder_name(
loadbalancer["tenant_id"])
if listener["use_snat"]:
if self.conf.f5_snat_per_provider:
if self.conf.f5_snat_addresses_per_subnet > 0:
folder_name = self.get_folder_name(
loadbalancer["tenant_id"])
prvd_name = loadbalancer["provider"]
listener["snat_pool_name"] = folder_name + '_' + prvd_name
else:
if self.conf.f5_snat_addresses_per_subnet > 0:
listener["snat_pool_name"] = self.get_folder_name(
loadbalancer["tenant_id"])

pool = self.get_vip_default_pool(service)

Expand Down Expand Up @@ -595,7 +603,7 @@ def get_vlan(self, vip, bigip, network_id):

def _add_vlan_and_snat(self, listener, vip):

# snat
# set snat mode (automap/sant pool) to listener
if "use_snat" in listener and listener["use_snat"]:
vip['sourceAddressTranslation'] = {}
if "snat_pool_name" in listener:
Expand Down
Loading