Skip to content

Commit

Permalink
Fixes: Routeleak not happening in case of IPv6-SVC with ECMP
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Ranjeet R committed Mar 30, 2017
1 parent f143d36 commit 9a591c6
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 2 deletions.
13 changes: 13 additions & 0 deletions src/config/schema-transformer/config_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
Expand Down Expand Up @@ -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:
Expand All @@ -2677,6 +2689,7 @@ def create(self):
if self.partially_created:
self.destroy()
return
self.si_info = si_info
self.uve_send()
# end create

Expand Down
102 changes: 100 additions & 2 deletions src/config/schema-transformer/test/test_service_policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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

0 comments on commit 9a591c6

Please sign in to comment.