K8S Services: add support for SCTP

The Octavia API already supports SCTP, though the support for
Amphora driver and OVN driver is still in development. This change
ensures that Octavia loadbalancer has listeners and pools/members
created with SCTP protocol. Kuryr already handles the case where
listener's protocol is not supported by Octavia.

Partially-Implements: blueprint sctp-support
Change-Id: Ia320760807cdffacb91b45d858b90d79354ef962
This commit is contained in:
Tabitha Fasoyin 2021-01-04 11:42:37 +00:00
parent 500ff16481
commit c3e66123a5
4 changed files with 38 additions and 5 deletions

View File

@ -383,6 +383,12 @@ function configure_neutron_defaults {
--description "k8s service subnet UDP allowed" \
--remote-ip "$service_cidr" --ethertype "$KURYR_ETHERTYPE" --protocol udp \
"$service_pod_access_sg_id"
# Octavia supports SCTP load balancing, we need to also allow SCTP traffic
openstack --os-cloud devstack-admin --os-region "$REGION_NAME" \
security group rule create --project "$project_id" \
--description "k8s service subnet SCTP allowed" \
--remote-ip "$service_cidr" --ethertype "$KURYR_ETHERTYPE" --protocol sctp \
"$service_pod_access_sg_id"
if [[ "$KURYR_K8S_OCTAVIA_MEMBER_MODE" == "L3" ]]; then
if [ -n "$sg_ids" ]; then
@ -418,6 +424,12 @@ function configure_neutron_defaults {
--description "k8s pod subnet allowed from k8s-pod-subnet" \
--remote-ip "$pod_cidr" --ethertype "$KURYR_ETHERTYPE" --protocol udp \
"$octavia_pod_access_sg_id"
# Octavia supports SCTP load balancing, we need to also support SCTP traffic
openstack --os-cloud devstack-admin --os-region "$REGION_NAME" \
security group rule create --project "$project_id" \
--description "k8s pod subnet allowed from k8s-pod-subnet" \
--remote-ip "$pod_cidr" --ethertype "$KURYR_ETHERTYPE" --protocol sctp \
"$octavia_pod_access_sg_id"
if [ -n "$sg_ids" ]; then
sg_ids+=",${octavia_pod_access_sg_id}"
else

View File

@ -48,6 +48,7 @@ _OCTAVIA_TAGGING_VERSION = 2, 5
_OCTAVIA_DL_VERSION = 2, 13
_OCTAVIA_ACL_VERSION = 2, 12
_OCTAVIA_PROVIDER_VERSION = 2, 6
_OCTAVIA_SCTP_VERSION = 2, 23
# HTTP Codes raised by Octavia when a Resource already exists
OKAY_CODES = (409, 500)
@ -63,6 +64,7 @@ class LBaaSv2Driver(base.LBaaSDriver):
self._octavia_acls = False
self._octavia_double_listeners = False
self._octavia_providers = False
self._octavia_sctp = False
# Check if Octavia API supports tagging.
# TODO(dulek): *Maybe* this can be replaced with
# lbaas.get_api_major_version(version=_OCTAVIA_TAGGING_VERSION)
@ -79,6 +81,9 @@ class LBaaSv2Driver(base.LBaaSDriver):
if v >= _OCTAVIA_TAGGING_VERSION:
LOG.info('Octavia supports resource tags.')
self._octavia_tags = True
if v >= _OCTAVIA_SCTP_VERSION:
LOG.info('Octavia API supports SCTP protocol.')
self._octavia_sctp = True
else:
v_str = '%d.%d' % v
LOG.warning('[neutron_defaults]resource_tags is set, but Octavia '
@ -94,6 +99,9 @@ class LBaaSv2Driver(base.LBaaSDriver):
def providers_supported(self):
return self._octavia_providers
def sctp_supported(self):
return self._octavia_sctp
def get_octavia_version(self):
lbaas = clients.get_loadbalancer_client()
region_name = getattr(CONF.neutron, 'region_name', None)
@ -362,9 +370,8 @@ class LBaaSv2Driver(base.LBaaSDriver):
loadbalancer, listener, self._create_listener,
self._find_listener, interval=_LB_STS_POLL_SLOW_INTERVAL)
except os_exc.SDKException:
LOG.exception("Listener creation failed, most probably because "
"protocol %(prot)s is not supported",
{'prot': protocol})
LOG.exception("Failed when creating listener for loadbalancer "
"%r", loadbalancer['id'])
return None
# NOTE(maysams): When ovn-octavia provider is used
@ -726,6 +733,14 @@ class LBaaSv2Driver(base.LBaaSDriver):
return result
except os_exc.BadRequestException:
raise
except os_exc.HttpException as e:
if e.status_code == 501:
LOG.exception("Listener creation failed, most probably "
"because protocol %(prot)s is not supported",
{'prot': obj['protocol']})
return None
else:
raise
except os_exc.SDKException:
pass

View File

@ -591,6 +591,10 @@ class KuryrLoadBalancerHandler(k8s_base.ResourceEventHandler):
LOG.warning("Skipping listener creation for %s as another one"
" already exists with port %s", name, port)
continue
if protocol == "SCTP" and not self._drv_lbaas.sctp_supported():
LOG.warning("Skipping listener creation as provider does"
" not support %s protocol", protocol)
continue
listener = self._drv_lbaas.ensure_listener(
loadbalancer=loadbalancer_crd['status'].get('loadbalancer'),
protocol=protocol,

View File

@ -173,11 +173,13 @@ class TestUtils(test_base.TestCase):
def test_get_service_ports(self):
service = {'spec': {'ports': [
{'port': 1, 'targetPort': 1},
{'port': 2, 'name': 'X', 'protocol': 'UDP', 'targetPort': 2}
{'port': 2, 'name': 'X', 'protocol': 'UDP', 'targetPort': 2},
{'port': 3, 'name': 'Y', 'protocol': 'SCTP', 'targetPort': 3}
]}}
expected_ret = [
{'port': 1, 'name': None, 'protocol': 'TCP', 'targetPort': '1'},
{'port': 2, 'name': 'X', 'protocol': 'UDP', 'targetPort': '2'}]
{'port': 2, 'name': 'X', 'protocol': 'UDP', 'targetPort': '2'},
{'port': 3, 'name': 'Y', 'protocol': 'SCTP', 'targetPort': '3'}]
ret = utils.get_service_ports(service)
self.assertEqual(expected_ret, ret)