From 051e70dd538adfde033fbc355bd24adc4595fcf5 Mon Sep 17 00:00:00 2001 From: Sachin Bansal Date: Fri, 23 Oct 2015 15:53:35 -0700 Subject: [PATCH] Keep track of ri refs on vmi and update accordingly Schema transformer needs to keep track of routing instance refs from virtual machine interfaces and update the links appropriately in api server. In 2.20, we always refresh vmi object before updating pbf rules. In mainline, we are adding code to keep track of these references to avoid unnecessary calls to api server. Change-Id: I5df1a16de477828e600df3f93f1589266d50ebfd Closes-Bug: 1509063 --- src/config/schema-transformer/config_db.py | 119 ++++++++++++--------- 1 file changed, 70 insertions(+), 49 deletions(-) diff --git a/src/config/schema-transformer/config_db.py b/src/config/schema-transformer/config_db.py index ff4e94328fd..39d25f3695e 100644 --- a/src/config/schema-transformer/config_db.py +++ b/src/config/schema-transformer/config_db.py @@ -1706,7 +1706,9 @@ def __init__(self, name, obj=None): remote_ri_fq_name = connection.split(':') if remote_ri_fq_name[-1] == remote_ri_fq_name[-2]: vn.connections.add(':'.join(remote_ri_fq_name[0:-1] )) - + vmi_refs = self.obj.get_virtual_machine_interface_back_refs() or [] + self.virtual_machine_interfaces = set([':'.join(ref['to']) + for ref in vmi_refs]) # end __init__ def update(self, obj=None): @@ -1798,7 +1800,7 @@ def add_connection(self, ri2): conn_data = ConnectionType() self.obj.add_routing_instance(ri2.obj, conn_data) self._vnc_lib.ref_update('routing-instance', self.obj.uuid, - 'routing_instance_refs', ri2.obj.uuid, + 'routing-instance', ri2.obj.uuid, None, 'ADD', conn_data) # end add_connection @@ -1807,7 +1809,7 @@ def delete_connection(self, ri2): ri2.connections.discard(self.name) try: self._vnc_lib.ref_update('routing-instance', self.obj.uuid, - 'routing_instance_refs', ri2.obj.uuid, + 'routing-instance', ri2.obj.uuid, None, 'DELETE') except NoIdError: return @@ -1904,9 +1906,8 @@ def delete_obj(self): if ri2: ri2.connections.discard(self.name) - # refresh the ri object because it could have changed rtgt_list = self.obj.get_route_target_refs() - DBBaseST._cassandra.free_route_target(self.name) + self._cassandra.free_route_target(self.name) service_chain = self.service_chain vn_obj = VirtualNetworkST.get(self.virtual_network) @@ -1914,25 +1915,18 @@ def delete_obj(self): vn_obj.free_service_chain_ip(self.obj.name) uve = UveServiceChainData(name=service_chain, deleted=True) - uve_msg = UveServiceChain(data=uve, sandesh=DBBaseST._sandesh) - uve_msg.send(sandesh=DBBaseST._sandesh) - - # read-back to get vmi backrefs on RI - try: - obj = self.read_vnc_obj(self.obj.uuid) - self.obj = obj - vmi_refs = self.obj.get_virtual_machine_interface_back_refs() or [] - for vmi in vmi_refs: - vmi_obj = self.read_vnc_obj( - vmi['uuid'], obj_type='virtual_machine_interface') - if service_chain is not None: - DBBaseST._cassandra.free_service_chain_vlan( - vmi_obj.get_parent_fq_name_str(), service_chain) - vmi_obj.del_routing_instance(self.obj) - DBBaseST._vnc_lib.virtual_machine_interface_update(vmi_obj) - # end for vmi - except NoIdError: - pass + uve_msg = UveServiceChain(data=uve, sandesh=self._sandesh) + uve_msg.send(sandesh=self._sandesh) + + for vmi_name in list(self.virtual_machine_interfaces): + vmi = VirtualMachineInterfaceST.get(vmi_name) + if vmi: + vm = VirtualMachineST.get(vmi.virtual_machine) + if vm is not None: + self._cassandra.free_service_chain_vlan(vm.uuid, + service_chain) + vmi.delete_routing_instance(self) + # end for vmi_name try: DBBaseST._vnc_lib.routing_instance_delete(id=self.obj.uuid) @@ -2106,7 +2100,7 @@ def check_create(self): if vm_obj is None: self.log_error('virtual machine %s not found' % service_vm) return None - vm_info = {'vm_obj': vm_obj} + vm_info = {'vm_uuid': vm_obj.uuid} for interface_name in vm_obj.virtual_machine_interfaces: interface = VirtualMachineInterfaceST.get(interface_name) @@ -2268,43 +2262,31 @@ def _create(self, si_info): self._cassandra.add_service_chain_uuid(self.name, jsonpickle.encode(self)) # end _create - def add_pbf_rule(self, vmi, ri1, ri2, v4_address, v6_address, vlan): + def add_pbf_rule(self, vmi, ri, v4_address, v6_address, vlan): if vmi.service_interface_type not in ["left", "right"]: return - refs = vmi.obj.get_routing_instance_refs() or [] - ri_refs = [ref['to'] for ref in refs] - pbf = PolicyBasedForwardingRuleType() - pbf.set_direction('both') - pbf.set_vlan_tag(vlan) - pbf.set_service_chain_address(v4_address) - pbf.set_ipv6_service_chain_address(v6_address) + pbf = PolicyBasedForwardingRuleType( + direction='both', vlan_tag=vlan, service_chain_address=v4_address, + ipv6_service_chain_address=v6_address) - update = False if vmi.service_interface_type == 'left': pbf.set_src_mac('02:00:00:00:00:01') pbf.set_dst_mac('02:00:00:00:00:02') - if (ri1.get_fq_name() not in ri_refs): - vmi.obj.add_routing_instance(ri1.obj, pbf) - update = True - if vmi.service_interface_type == 'right' and self.direction == '<>': + else: pbf.set_src_mac('02:00:00:00:00:02') pbf.set_dst_mac('02:00:00:00:00:01') - if (ri2.get_fq_name() not in ri_refs): - vmi.obj.add_routing_instance(ri2.obj, pbf) - update = True - if update: - self._vnc_lib.virtual_machine_interface_update(vmi.obj) + + vmi.add_routing_instance(ri, pbf) # end add_pbf_rule def process_transparent_service(self, vm_info, v4_address, v6_address, service_ri1, service_ri2): - vm_uuid = vm_info['vm_obj'].uuid - vlan = self._cassandra.allocate_service_chain_vlan(vm_uuid, + vlan = self._cassandra.allocate_service_chain_vlan(vm_info['vm_uuid'], self.name) - self.add_pbf_rule(vm_info['left']['vmi'], service_ri1, service_ri2, + self.add_pbf_rule(vm_info['left']['vmi'], service_ri1, v4_address, v6_address, vlan) - self.add_pbf_rule(vm_info['right']['vmi'], service_ri1, service_ri2, + self.add_pbf_rule(vm_info['right']['vmi'], service_ri2, v4_address, v6_address, vlan) return True # end process_transparent_service @@ -2562,6 +2544,7 @@ def __init__(self, name, obj=None): self.uuid = None self.instance_ips = set() self.floating_ips = set() + self.routing_instances = {} self.obj = obj or self.read_vnc_obj(fq_name=name) self.uuid = self.obj.uuid self.update_multiple_refs('instance_ip', self.obj) @@ -2580,6 +2563,7 @@ def update(self, obj=None): self.update_single_ref('virtual_machine', self.obj) self.update_single_ref('logical_router', self.obj) self.set_properties() + self.update_routing_instances(self.obj.get_routing_instance_refs()) # end update def delete_obj(self): @@ -2588,6 +2572,7 @@ def delete_obj(self): self.update_single_ref('logical_router', {}) self.update_multiple_refs('instance_ip', {}) self.update_multiple_refs('floating_ip', {}) + self.update_routing_instances([]) # end delete_obj def evaluate(self): @@ -2617,6 +2602,42 @@ def set_properties(self): self.interface_mirror = None # end set_properties + def update_routing_instances(self, ri_refs): + routing_instances = dict((':'.join(ref['to']), ref['attr']) + for ref in ri_refs or []) + old_ri_set = set(self.routing_instances.keys()) + new_ri_set = set(routing_instances.keys()) + for ri_name in old_ri_set - new_ri_set: + ri = RoutingInstanceST.get(ri_name) + if ri: + ri.virtual_machine_interfaces.discard(self.name) + for ri_name in new_ri_set - old_ri_set: + ri = RoutingInstanceST.get(ri_name) + if ri: + ri.virtual_machine_interfaces.add(self.name) + self.routing_instances = routing_instances + # end update_routing_instances + + def add_routing_instance(self, ri, pbf): + if self.routing_instances.get(ri.name) == pbf: + return + self._vnc_lib.ref_update( + 'virtual-machine-interface', self.uuid, 'routing-instance', + ri.obj.uuid, None, 'ADD', pbf) + self.routing_instances[ri.name] = pbf + ri.virtual_machine_interfaces.add(self.name) + # end add_routing_instance + + def delete_routing_instance(self, ri): + if ri.name not in self.routing_instances: + return + self._vnc_lib.ref_update( + 'virtual-machine-interface', self.uuid, 'routing-instance', + ri.obj.uuid, None, 'DELETE') + del self.routing_instances[ri.name] + ri.virtual_machine_interfaces.discard(self.name) + # end delete_routing_instance + def _add_pbf_rules(self): if (not self.virtual_machine or self.service_interface_type not in ['left', 'right']): @@ -2648,8 +2669,8 @@ def _add_pbf_rules(self): vlan = self._cassandra.allocate_service_chain_vlan( vm_obj.uuid, service_chain.name) - service_chain.add_pbf_rule(self, service_ri, service_ri, - v4_address, v6_address, vlan) + service_chain.add_pbf_rule(self, service_ri, v4_address, + v6_address, vlan) # end _add_pbf_rules def set_virtual_network(self):