diff --git a/devstack/plugin.sh b/devstack/plugin.sh index de70f5f5f..f719c3170 100644 --- a/devstack/plugin.sh +++ b/devstack/plugin.sh @@ -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 diff --git a/kuryr_kubernetes/controller/drivers/lbaasv2.py b/kuryr_kubernetes/controller/drivers/lbaasv2.py index 2c53ab03b..5dd7b972f 100644 --- a/kuryr_kubernetes/controller/drivers/lbaasv2.py +++ b/kuryr_kubernetes/controller/drivers/lbaasv2.py @@ -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 diff --git a/kuryr_kubernetes/controller/handlers/loadbalancer.py b/kuryr_kubernetes/controller/handlers/loadbalancer.py index d9578652b..66244ab61 100644 --- a/kuryr_kubernetes/controller/handlers/loadbalancer.py +++ b/kuryr_kubernetes/controller/handlers/loadbalancer.py @@ -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, diff --git a/kuryr_kubernetes/tests/unit/test_utils.py b/kuryr_kubernetes/tests/unit/test_utils.py index 4b0a0785a..2bceedcec 100644 --- a/kuryr_kubernetes/tests/unit/test_utils.py +++ b/kuryr_kubernetes/tests/unit/test_utils.py @@ -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)