From 9a591c6242775a45a4f81f2a00f0d50fa0fd7d67 Mon Sep 17 00:00:00 2001 From: Ranjeet R Date: Fri, 24 Mar 2017 16:07:24 -0700 Subject: [PATCH] Fixes: Routeleak not happening in case of IPv6-SVC with ECMP The IPv6 Address gets assigned after the SI is created sometimes causing the si_info not to be populated. The fix is to check for the SI info even if the SC is created and recreate SC object if it is different. UT Added for checking the IPv6 address in the service chain. Change-Id: I9a020d553853ead0e8e2e90c856ab3f8575961df Closes-Bug: 1670320 --- src/config/schema-transformer/config_db.py | 13 +++ .../test/test_service_policy.py | 102 +++++++++++++++++- 2 files changed, 113 insertions(+), 2 deletions(-) diff --git a/src/config/schema-transformer/config_db.py b/src/config/schema-transformer/config_db.py index 163da28f04d..f0029d82207 100644 --- a/src/config/schema-transformer/config_db.py +++ b/src/config/schema-transformer/config_db.py @@ -2474,6 +2474,8 @@ def init(cls): chain.created_stale = chain.created if not hasattr(chain, 'partially_created'): chain.partially_created = False + if not hasattr(chain, 'si_info'): + chain.si_info = None cls._dict[name] = chain # end init @@ -2486,6 +2488,7 @@ def __init__(self, name, left_vn, right_vn, direction, sp_list, dp_list, self.sp_list = sp_list self.dp_list = dp_list self.service_list = list(services) + self.si_info = None self.protocol = protocol self.created = False @@ -2669,6 +2672,15 @@ def create(self): if si_info is None: # if previously created but no longer valid, then destroy self.destroy() + + # If the VMIs associated with the SC has changed + # after the SC is created, recreate the SC object. + if self.si_info != None and si_info != self.si_info: + self._create(si_info) + self.si_info = si_info + if self.partially_created: + self.destroy() + return return if si_info is None: @@ -2677,6 +2689,7 @@ def create(self): if self.partially_created: self.destroy() return + self.si_info = si_info self.uve_send() # end create diff --git a/src/config/schema-transformer/test/test_service_policy.py b/src/config/schema-transformer/test/test_service_policy.py index 1f33dd8670c..01131ee50bf 100644 --- a/src/config/schema-transformer/test/test_service_policy.py +++ b/src/config/schema-transformer/test/test_service_policy.py @@ -29,6 +29,8 @@ from test_utils import CassandraCFs import test_common from unittest import skip +from netaddr import IPNetwork, IPAddress +import uuid class VerifyServicePolicy(VerifyPolicy): @@ -49,8 +51,12 @@ def wait_to_get_sc(self, left_vn=None, right_vn=None, si_name=None, @retries(5) def check_service_chain_prefix_match(self, fq_name, prefix): + ip_version = IPNetwork(prefix).version ri = self._vnc_lib.routing_instance_read(fq_name) - sci = ri.get_service_chain_information() + if ip_version == 6: + sci = ri.get_ipv6_service_chain_information() + else: + sci = ri.get_service_chain_information() if sci is None: print "retrying ... ", test_common.lineno() raise Exception('Service chain info not found for %s' % fq_name) @@ -1880,7 +1886,7 @@ def test_service_policy_vmi_with_multi_port_tuples(self): vn1_obj.del_network_policy(np) vn2_obj.del_network_policy(np) - vn2_obj.del_network_policy(np) + vn3_obj.del_network_policy(np) self._vnc_lib.virtual_network_update(vn1_obj) self._vnc_lib.virtual_network_update(vn2_obj) @@ -1924,4 +1930,96 @@ def test_mps_with_nat(self, version=2): self._vnc_lib.virtual_network_delete(fq_name=vn1_obj.get_fq_name()) self._vnc_lib.virtual_network_delete(fq_name=vn2_obj.get_fq_name()) # end test_mps_with_nat + + def assign_vn_subnet(self, vn_obj, subnet_list): + subnet_info = [] + for subnet in subnet_list: + cidr = IPNetwork(subnet) + subnet_info.append(IpamSubnetType( + subnet = SubnetType( + str(cidr.network), + int(cidr.prefixlen), + ), + default_gateway = str(IPAddress(cidr.last - 1)), + subnet_uuid = str(uuid.uuid4()), + ) + ) + ipam_fq_name = [ + 'default-domain', 'default-project', 'default-network-ipam'] + ipam_obj = self._vnc_lib.network_ipam_read(fq_name=ipam_fq_name) + subnet_data = VnSubnetsType(subnet_info) + vn_obj.add_network_ipam(ipam_obj, subnet_data) + self._vnc_lib.virtual_network_update(vn_obj) + vn_obj.clear_pending_updates() + + def test_service_policy_with_v4_v6_subnets(self): + + # If the SC chain info changes after the SI is created + # (for example, IP address assignment) then the + # RI needs to be updated with the new info. + + # Create VN without subnets + vn1_name = self.id() + 'vn1' + vn2_name = self.id() + 'vn2' + vn1_obj = VirtualNetwork(name=vn1_name) + self._vnc_lib.virtual_network_create(vn1_obj) + vn2_obj = VirtualNetwork(name=vn2_name) + self._vnc_lib.virtual_network_create(vn2_obj) + + # Create SC + service_name = self.id() + 's1' + np = self.create_network_policy(vn1_obj, vn2_obj, [service_name], version=2) + seq = SequenceType(1, 1) + vnp = VirtualNetworkPolicyType(seq) + + vn1_obj.set_network_policy(np, vnp) + vn2_obj.set_network_policy(np, vnp) + self._vnc_lib.virtual_network_update(vn1_obj) + self._vnc_lib.virtual_network_update(vn2_obj) + sc = self.wait_to_get_sc() + + # Assign prefix after the SC is created + self.assign_vn_subnet(vn1_obj, ['10.0.0.0/24', '1000::/16']) + self.assign_vn_subnet(vn2_obj, ['20.0.0.0/24', '2000::/16']) + + sc_ri_name = 'service-'+sc+'-default-domain_default-project_' + service_name + self.check_ri_ref_present(self.get_ri_name(vn1_obj), + self.get_ri_name(vn1_obj, sc_ri_name)) + self.check_ri_ref_present(self.get_ri_name(vn2_obj, sc_ri_name), + self.get_ri_name(vn2_obj)) + + # Checking the Service chain address in the service RI + v4_service_chain_address = '10.0.0.251' + v6_service_chain_address = '1000:ffff:ffff:ffff:ffff:ffff:ffff:fffb' + + sci = ServiceChainInfo(prefix = ['10.0.0.0/24'], + routing_instance = ':'.join(self.get_ri_name(vn1_obj)), + service_chain_address = v4_service_chain_address, + service_instance = 'default-domain:default-project:' + service_name) + self.check_service_chain_info(self.get_ri_name(vn2_obj, sc_ri_name), sci) + sci.prefix = ['1000::/16'] + sci.service_chain_address = v6_service_chain_address + self.check_v6_service_chain_info(self.get_ri_name(vn2_obj, sc_ri_name), sci) + sci = ServiceChainInfo(prefix = ['20.0.0.0/24'], + routing_instance = ':'.join(self.get_ri_name(vn2_obj)), + service_chain_address = v4_service_chain_address, + service_instance = 'default-domain:default-project:' + service_name) + self.check_service_chain_info(self.get_ri_name(vn1_obj, sc_ri_name), sci) + sci.prefix = ['2000::/16'] + sci.service_chain_address = v6_service_chain_address + self.check_v6_service_chain_info(self.get_ri_name(vn1_obj, sc_ri_name), sci) + + left_ri_fq_name = ['default-domain', 'default-project', vn1_name, sc_ri_name] + right_ri_fq_name = ['default-domain', 'default-project', vn2_name, sc_ri_name] + self.check_service_chain_prefix_match(left_ri_fq_name, prefix='2000::/16') + self.check_service_chain_prefix_match(left_ri_fq_name, prefix='20.0.0.0/24') + self.check_service_chain_prefix_match(right_ri_fq_name, prefix='1000::/16') + self.check_service_chain_prefix_match(right_ri_fq_name, prefix='10.0.0.0/24') + + vn2_obj.del_network_policy(np) + self._vnc_lib.virtual_network_update(vn2_obj) + vn1_obj.del_network_policy(np) + self._vnc_lib.virtual_network_update(vn1_obj) + self._vnc_lib.network_policy_delete(id=np.uuid) + #end test_service_policy_with_v4_v6_subnets # end class TestServicePolicy