Beispiel #1
0
 def show_details_client_type(self, client_type):
     '''
     Display the details of a Tunnel given a client_type
     '''
     try:
         vnid_hash = self.DVG_Hash[client_type]
         vnid_hash_ip = self.VNID_Hash_IP[client_type]
         ip_hash_vnid = self.IP_Hash_VNID[client_type]
         client_type_string = DpsClientType.types[client_type]
         print 'Tunnel Type %s\r'%client_type_string
         print 'VNIDS %s\r'%vnid_hash.keys()
         for vnid, vnid_ips in vnid_hash_ip.items():
             ip_list = IPAddressList(socket.AF_INET)
             for vnid_ip in vnid_ips:
                 try:
                     ip_list.add(socket.AF_INET, vnid_ip)
                 except Exception:
                     pass
             print 'VNID %s, PIPv4s %s\r'%(vnid, ip_list.toString())
         for ip, ip_vnids in ip_hash_vnid.items():
             try:
                 ip_packed = struct.pack(IPAddressList.fmts[socket.AF_INET], ip)
                 ip_string = socket.inet_ntop(socket.AF_INET, ip_packed)
             except Exception:
                 pass
             print 'PIPv4 %s, VNIDs %s\r'%(ip_string, ip_vnids.keys())
     except Exception:
         pass
     return
 def show_details_client_type(self, client_type):
     '''
     Display the details of a Tunnel given a client_type
     '''
     try:
         vnid_hash = self.DVG_Hash[client_type]
         vnid_hash_ip = self.VNID_Hash_IP[client_type]
         ip_hash_vnid = self.IP_Hash_VNID[client_type]
         client_type_string = DpsClientType.types[client_type]
         print 'Tunnel Type %s\r' % client_type_string
         print 'VNIDS %s\r' % vnid_hash.keys()
         for vnid, vnid_ips in vnid_hash_ip.items():
             ip_list = IPAddressList(socket.AF_INET)
             for vnid_ip in vnid_ips:
                 try:
                     ip_list.add(socket.AF_INET, vnid_ip)
                 except Exception:
                     pass
             print 'VNID %s, PIPv4s %s\r' % (vnid, ip_list.toString())
         for ip, ip_vnids in ip_hash_vnid.items():
             try:
                 ip_packed = struct.pack(IPAddressList.fmts[socket.AF_INET],
                                         ip)
                 ip_string = socket.inet_ntop(socket.AF_INET, ip_packed)
             except Exception:
                 pass
             print 'PIPv4 %s, VNIDs %s\r' % (ip_string, ip_vnids.keys())
     except Exception:
         pass
     return
Beispiel #3
0
 def __init__(self, fregister, domain, dvg, client_type, transaction_type, dps_client, pip_tuple_list):
     '''
     Constructor:
     This routine assumes that the 1st IP address in the tuple uniquely
     identifies a DOVE Switch/VLAN Gateway within the Domain.
     @param fregister: Whether this is an explicit tunnel register
     @param fregister: Boolean
     @param domain: The Domain object
     @type domain: Domain
     @param dvg: The DVG/VNID object
     @type dvg: DVG
     @param client_type: The Type of Client: should be in DpsClientType.types
     @type client_type: Integer 
     @param transaction_type: The Type of Transaction: should be in Domain.transaction_types
     @type transaction_type: Integer
     @param dps_client: The DPS Client associated with this Tunnel
     @type dps_client: DPSClient
     @type dps_client_port: Integer
     @param pip_tuple_array: A list of tuples of Physical IP Addresses, each 
                             tuple is of the form (inet_type, ip_value).
                             The inet_type = socket type i.e. AF_INET or AF_INET6
                             The ip_value = IPv4 in integer or IPv6 in string
     @type pip_tuple_array: List of tuples
     '''
     if len(pip_tuple_list) == 0:
         raise Exception('No IP Address Provided: Invalid DOVE Switch')
     try:
         client_string = DpsClientType.types[client_type]
     except Exception:
         raise Exception('Not a supported Tunnel Type')
     self.domain = domain
     #DPS Client Location i.e. the UDP Port and Location
     self.dps_client = dps_client
     #############################################################
     #Based on Object Model Chapter 5.3: DOVE Switch
     #############################################################
     #TODO: SQL Table of Policies: Requirement 1.3
     #Hash List of all Endpoints hashed by MAC: Requirement 1.4
     self.Endpoint_Hash_MAC = {}
     #A dictionary indexed by VNID IDs, the value is the number
     #of Endpoints on that DOVE Switch in a particular VNID/DVG
     self.DVG_Hash = {}
     inet_type = pip_tuple_list[0][0]
     ip_value = pip_tuple_list[0][1]
     #ip_location = IPAddressLocation(inet_type, ip_value, 0)
     #print 'Tunnel %s created DVG_Hash\r'%ip_location.show_ip()
     for ctype in DpsClientType.types.keys():
         self.DVG_Hash[ctype] = {}
     #Key IP_value: Value VNID
     self.IP_Hash_VNID = {}
     #print 'Tunnel %s created IP_Hash_VNID\r'%ip_location.show_ip()
     for ctype in DpsClientType.types.keys():
         self.IP_Hash_VNID[ctype] = {}
     #Key VNID: Value Hash of IPs
     self.VNID_Hash_IP = {}
     for ctype in DpsClientType.types.keys():
         self.VNID_Hash_IP[ctype] = {}
     #print 'Tunnel %s created VNID_Hash_IP\r'%ip_location.show_ip()
     #List of Physical IP Addresses
     self.ip_listv4 = IPAddressList(socket.AF_INET)
     self.ip_listv6 = IPAddressList(socket.AF_INET6)
     for i in range(len(pip_tuple_list)):
         inet_type = pip_tuple_list[i][0]
         ip_value = pip_tuple_list[i][1]
         self.ip_add(dvg, fregister, client_type, inet_type, ip_value, transaction_type)
     #############################################################
     #To be finished
     #############################################################
     #dcs_object.__init__(self, self.primary_ip().show())
     self.version = 0
     self.valid = True
     DPSClientHost.Host_Add(domain, dps_client.location.inet_type, 
                            dps_client.location.ip_value, dps_client.location.port, 
                            client_type)
Beispiel #4
0
class TunnelEndpoint:
    '''
    This represents a DOVE Underlay Tunnel in the DOVE environment -
    i.e DOVE Switch or VLAN Gateway.
    NOTE: Each Tunnel Endpoint will have multiple instances every every Domain
          it hosts Endpoints on. In other words if a TunnelEndpoint hosts
          endpoints on Domain A and Domain B, then there will be 2
          independent instances of that Tunnel Endpoint, 1 in Domain A and 1
          in Domain B.
    '''

    def __init__(self, fregister, domain, dvg, client_type, transaction_type, dps_client, pip_tuple_list):
        '''
        Constructor:
        This routine assumes that the 1st IP address in the tuple uniquely
        identifies a DOVE Switch/VLAN Gateway within the Domain.
        @param fregister: Whether this is an explicit tunnel register
        @param fregister: Boolean
        @param domain: The Domain object
        @type domain: Domain
        @param dvg: The DVG/VNID object
        @type dvg: DVG
        @param client_type: The Type of Client: should be in DpsClientType.types
        @type client_type: Integer 
        @param transaction_type: The Type of Transaction: should be in Domain.transaction_types
        @type transaction_type: Integer
        @param dps_client: The DPS Client associated with this Tunnel
        @type dps_client: DPSClient
        @type dps_client_port: Integer
        @param pip_tuple_array: A list of tuples of Physical IP Addresses, each 
                                tuple is of the form (inet_type, ip_value).
                                The inet_type = socket type i.e. AF_INET or AF_INET6
                                The ip_value = IPv4 in integer or IPv6 in string
        @type pip_tuple_array: List of tuples
        '''
        if len(pip_tuple_list) == 0:
            raise Exception('No IP Address Provided: Invalid DOVE Switch')
        try:
            client_string = DpsClientType.types[client_type]
        except Exception:
            raise Exception('Not a supported Tunnel Type')
        self.domain = domain
        #DPS Client Location i.e. the UDP Port and Location
        self.dps_client = dps_client
        #############################################################
        #Based on Object Model Chapter 5.3: DOVE Switch
        #############################################################
        #TODO: SQL Table of Policies: Requirement 1.3
        #Hash List of all Endpoints hashed by MAC: Requirement 1.4
        self.Endpoint_Hash_MAC = {}
        #A dictionary indexed by VNID IDs, the value is the number
        #of Endpoints on that DOVE Switch in a particular VNID/DVG
        self.DVG_Hash = {}
        inet_type = pip_tuple_list[0][0]
        ip_value = pip_tuple_list[0][1]
        #ip_location = IPAddressLocation(inet_type, ip_value, 0)
        #print 'Tunnel %s created DVG_Hash\r'%ip_location.show_ip()
        for ctype in DpsClientType.types.keys():
            self.DVG_Hash[ctype] = {}
        #Key IP_value: Value VNID
        self.IP_Hash_VNID = {}
        #print 'Tunnel %s created IP_Hash_VNID\r'%ip_location.show_ip()
        for ctype in DpsClientType.types.keys():
            self.IP_Hash_VNID[ctype] = {}
        #Key VNID: Value Hash of IPs
        self.VNID_Hash_IP = {}
        for ctype in DpsClientType.types.keys():
            self.VNID_Hash_IP[ctype] = {}
        #print 'Tunnel %s created VNID_Hash_IP\r'%ip_location.show_ip()
        #List of Physical IP Addresses
        self.ip_listv4 = IPAddressList(socket.AF_INET)
        self.ip_listv6 = IPAddressList(socket.AF_INET6)
        for i in range(len(pip_tuple_list)):
            inet_type = pip_tuple_list[i][0]
            ip_value = pip_tuple_list[i][1]
            self.ip_add(dvg, fregister, client_type, inet_type, ip_value, transaction_type)
        #############################################################
        #To be finished
        #############################################################
        #dcs_object.__init__(self, self.primary_ip().show())
        self.version = 0
        self.valid = True
        DPSClientHost.Host_Add(domain, dps_client.location.inet_type, 
                               dps_client.location.ip_value, dps_client.location.port, 
                               client_type)
        #print 'Tunnel %s created\r'%ip_location.show_ip()

    def endpoint_add(self, endpoint, transaction_type):
        '''
        Adds an Endpoint to the DOVE Tunnel
        @param transaction_type: The Type of Transaction: should be in Domain.transaction_types
        @type transaction_type: Integer
        '''
        #log.info('Tunnel.endpoint_add')
        #self.show(None)
        self.Endpoint_Hash_MAC[endpoint.vMac] = endpoint
        #self.show()
        return

    def endpoint_del(self, endpoint):
        '''
        Deletes an Endpoint from the DOVE Tunnel Endpoint
        '''
        try:
            del self.Endpoint_Hash_MAC[endpoint.vMac]
        except Exception:
            pass
        #self.show()
        if self.domain.unique_id == 0:
            #Remove the Tunnel Endpoint if no other Endpoints exist for Domain 0
            self.delete_if_empty()
        return

    def ip_add(self, dvg, fregister, client_type, inet_type, ip_value, transaction_type):
        '''
        This adds a tunnel IP address
        @param dvg: The DVG on which this registration occurred
        @type dvg: DVG
        @param fregister: Whether this is an explicit tunnel register
        @param fregister: Boolean
        @param client_type: The Type of Client: should be in DpsClientType.types
        @type client_type: Integer 
        @param inet_type: AF_INET or AF_INET6
        @type inet_type: Integer
        @param ip_value: The IP address value
        @type ip_value: Integer or String
        @param transaction_type: The Type of Transaction: should be in DpsTransactionType
        @type transaction_type: Integer
        '''
        while True:
            try:
                client_type_value = DpsClientType.types[client_type]
            except Exception:
                break
            self.DVG_Hash[client_type][dvg.unique_id] = dvg
            #Add to Tunnels List even though it may have come through other DVGs as well
            if inet_type == socket.AF_INET:
                if not self.ip_listv4.search(ip_value):
                    self.ip_listv4.add(inet_type, ip_value)
            elif inet_type == socket.AF_INET6:
                if not self.ip_listv4.search(ip_value):
                    self.ip_listv6.add(inet_type, ip_value)
            #log.info('ip_add: Adding to DPS Client %s', ip_value)
            #Add DVG to self.
            #Add IP to DPS Client
            DPSClient.tunnel_endpoint_add_IP(self.dps_client, self, inet_type, ip_value)
            #Add IP to this DVGs
            DVG.tunnel_endpoint_add_IP(dvg, fregister, self, client_type, inet_type, ip_value, transaction_type)
            try:
                vnid_hash_ip = self.VNID_Hash_IP[client_type][dvg.unique_id]
            except Exception:
                self.VNID_Hash_IP[client_type][dvg.unique_id] = {}
                vnid_hash_ip = self.VNID_Hash_IP[client_type][dvg.unique_id]
            vnid_hash_ip[ip_value] = True
            #Add DVGs to IP hash
            try:
                ip_hash_vnid = self.IP_Hash_VNID[client_type][ip_value]
            except Exception:
                self.IP_Hash_VNID[client_type][ip_value] = {}
                ip_hash_vnid = self.IP_Hash_VNID[client_type][ip_value]
            ip_hash_vnid[dvg.unique_id] = True 
            #Add IP to Domain
            #log.info('ip_add: Adding to domain %s', self.domain.unique_id)
            Domain.tunnel_endpoint_add_IP(self.domain, self, inet_type, ip_value)
            break
        return

    def ip_delete(self, dvg, client_type, inet_type, ip_value):
        '''
        This deletes a tunnel IP address from a DVG and client type
        @param dvg: The DVG on which this registration occurred
        @type dvg: DVG
        @param client_type: The Type of Client: should be in DpsClientType.types
        @type client_type: Integer 
        @param inet_type: AF_INET or AF_INET6
        @type inet_type: Integer
        @param ip_value: The IP address value
        @type ip_value: Integer or String
        '''
        fdeleteVNID = False
        fdeleteIP = False
        while True:
            try:
                client_type_value = DpsClientType.types[client_type]
            except Exception:
                break
            try:
                vnid_hash_ip = self.VNID_Hash_IP[client_type][dvg.unique_id]
                del vnid_hash_ip[ip_value]
                if len(vnid_hash_ip) == 0:
                    del self.VNID_Hash_IP[client_type][dvg.unique_id]
                    fdeleteVNID = True
            except Exception:
                pass
            try:
                ip_hash_vnid = self.IP_Hash_VNID[client_type][ip_value]
                del ip_hash_vnid[dvg.unique_id]
                if len(ip_hash_vnid) == 0:
                    del self.IP_Hash_VNID[client_type][ip_value]
                    fdeleteIP = True
            except Exception:
                pass
            if fdeleteVNID:
                #Remove Tunnel from DVG
                DVG.tunnel_endpoint_delete(dvg, self, client_type)
                try:
                    del self.DVG_Hash[client_type][dvg.unique_id]
                    if len(self.DVG_Hash[client_type]) == 0:
                        #print 'Delete all Endpoints with client_type %s\r'%client_type_value
                        self.delete_client_type(client_type)
                except Exception:
                    pass
            if not fdeleteIP:
                break
            if fdeleteIP:
                #Remove only the IP from the DVG
                DVG.tunnel_endpoint_delete_IP(dvg, client_type, inet_type, ip_value)
            #Check if IP is present in any client type
            ip_present = False
            for ctype in self.IP_Hash_VNID.keys():
                try:
                    ip_hash_vnid = self.IP_Hash_VNID[ctype][ip_value]
                    ip_present = True
                    break
                except Exception:
                    continue
            if ip_present:
                break
            #Actually delete the IP from Domain and DPS Clients since no DVGs have it
            if inet_type == socket.AF_INET:
                self.ip_listv4.remove(inet_type, ip_value)
            elif inet_type == socket.AF_INET6:
                self.ip_listv6.remove(inet_type, ip_value)
            #Remove IP to DPS Client
            DPSClient.tunnel_endpoint_delete_IP(self.dps_client, inet_type, ip_value)
            #Remove IP from Domain
            Domain.tunnel_endpoint_delete_IP(self.domain, inet_type, ip_value)
            #Delete Self if not IP Addresses are present
            if self.ip_listv4.count() == 0 and self.ip_listv6.count() == 0:
                self.delete()
            break
        return

    def ip_clear(self, inet_type, ip_value):
        '''
        This deletes a tunnel IP address from this Tunnel and all DVGS and types
        @param dvg: The DVG on which this registration occurred
        @type dvg: DVG
        @param client_type: The Type of Client: should be in DpsClientType.types
        @type client_type: Integer 
        @param inet_type: AF_INET or AF_INET6
        @type inet_type: Integer
        @param ip_value: The IP address value
        @type ip_value: Integer or String
        '''
        while True:
            for client_type in DpsClientType.types.keys():
                #Delete IP from all matching VNIDs and Client Type
                for vnid in self.DVG_Hash[client_type].keys():
                    fRemoveVNID = False
                    try:
                        vnid_hash_ip = self.VNID_Hash_IP[client_type][vnid]
                        del vnid_hash_ip[ip_value]
                        if len(vnid_hash_ip) == 0:
                            del self.VNID_Hash_IP[client_type][vnid]
                            fRemoveVNID = True
                    except Exception:
                        pass
                    #Remove the IP from the DVG
                    try:
                        dvg = self.DVG_Hash[client_type][vnid]
                        DVG.tunnel_endpoint_delete_IP(dvg, client_type, inet_type, ip_value)
                        if fRemoveVNID:
                            del self.DVG_Hash[client_type][vnid]
                            if len(self.DVG_Hash[client_type]) == 0:
                                #print 'Delete all Endpoints with client_type %s\r'%client_type
                                self.delete_client_type(client_type)
                    except Exception:
                        pass
                #Delete IP completly from Tunnel
                try:
                    ip_hash_vnid = self.IP_Hash_VNID[client_type][ip_value]
                    ip_hash_vnid.clear()
                    del self.IP_Hash_VNID[client_type][ip_value]
                except Exception:
                    pass
            #Delete the IP from Domain and DPS Clients since no DVGs have it
            if inet_type == socket.AF_INET:
                self.ip_listv4.remove(inet_type, ip_value)
            elif inet_type == socket.AF_INET6:
                self.ip_listv6.remove(inet_type, ip_value)
            #Remove IP to DPS Client
            DPSClient.tunnel_endpoint_delete_IP(self.dps_client, inet_type, ip_value)
            #Remove IP from Domain
            Domain.tunnel_endpoint_delete_IP(self.domain, inet_type, ip_value)
            #Delete Self if not IP Addresses are present
            if self.ip_listv4.count() == 0 and self.ip_listv6.count() == 0:
                self.delete()
            break
        return

    def delete_if_empty(self):
        '''
        This routine checks if a DPS Client no longer hosts any Endpoint.
        If it doesn't, it unlinks itself from all the domain
        '''
        if len(self.Endpoint_Hash_MAC) != 0:
            return
        if not self.valid:
            return
        self.valid = False
        #Remove self from all DVGs
        for client_type in DpsClientType.types.keys():
            for dvg in self.DVG_Hash[client_type].values():
                DVG.tunnel_endpoint_delete(dvg, self, client_type)
        #Clear the VNID/DVG Hash
        self.DVG_Hash.clear()
        #Remove from DPS Client Collection
        DPSClient.tunnel_endpoint_delete(self.dps_client, self)
        #Remove from Domain Collection
        Domain.tunnel_endpoint_delete(self.domain, self)
        #Clear IPs
        self.ip_listv4.clear()
        self.ip_listv6.clear()
        return

    def delete(self):
        '''
        Destructor:
        '''
        #Lose references to all endpoint objects
        for endpoint in self.Endpoint_Hash_MAC.values():
            endpoint.delete()
        self.Endpoint_Hash_MAC.clear()
        #Now call delete_if_empty
        self.delete_if_empty()
        return

    def delete_client_type(self, client_type):
        '''
        Remove association with a particular client type
        '''
        for endpoint_key in self.Endpoint_Hash_MAC.keys():
            try:
                endpoint = self.Endpoint_Hash_MAC[endpoint_key]
            except Exception:
                continue
            if endpoint.client_type == client_type:
                endpoint.delete()
        return

    def primary_ip(self):
        '''
        This routine shows any one IP Address to represent the Tunnel
        '''
        try:
            ip = self.ip_listv4.get_primary()
            return IPAddressLocation(socket.AF_INET, ip, 0)
        except Exception:
            pass
        try:
            ip = self.ip_listv6.get_primary()
            return IPAddressLocation(socket.AF_INET6, ip, 0)
        except Exception:
            pass
        return IPAddressLocation(socket.AF_INET, 0, 0)

    def tunnel_types_supported(self):
        '''
        This routine lists the tunnel type hosted by this tunnel
        '''
        tunnel_types = []
        for tunnel_type in DpsClientType.types.keys():
            try:
                dvg_hash = self.DVG_Hash[tunnel_type]
                if len(dvg_hash) == 0:
                    continue
                tunnel_types.append(tunnel_type)
            except Exception:
                pass
        return tunnel_types

    @staticmethod
    def merge_tunnels(tunnel_primary, tunnel_secondary):
        '''
        This routine merges the content of secondary tunnel into the primary tunnel
        and deletes the secondary tunnel
        '''
        #Copy Endpoints
        tunnel_primary.Endpoint_Hash_MAC = dict(tunnel_primary.Endpoint_Hash_MAC.items() + tunnel_secondary.Endpoint_Hash_MAC.items())
        tunnel_secondary.Endpoint_Hash_MAC.clear()
        #Copy DVGs
        for ctype in DpsClientType.types.keys():
            tunnel_primary.DVG_Hash[ctype] = dict(tunnel_primary.DVG_Hash[ctype].items() + tunnel_secondary.DVG_Hash[ctype].items())
            tunnel_secondary.DVG_Hash[ctype].clear()
        #Copy 
        for ctype in DpsClientType.types.keys():
            tunnel_primary.IP_Hash_VNID[ctype] = dict(tunnel_primary.IP_Hash_VNID[ctype].items() + tunnel_secondary.IP_Hash_VNID[ctype].items())
            tunnel_secondary.IP_Hash_VNID[ctype].clear()
        #Key VNID: Value Hash of IPs
        for ctype in DpsClientType.types.keys():
            tunnel_primary.VNID_Hash_IP[ctype] = dict(tunnel_primary.VNID_Hash_IP[ctype].items() + tunnel_secondary.VNID_Hash_IP[ctype].items())
            tunnel_secondary.VNID_Hash_IP[ctype].clear()
        #List of Physical IP Addresses
        ipv4_values = tunnel_secondary.ip_listv4.ip_hash.keys()
        tunnel_secondary.ip_listv4.clear()
        for ip_value in ipv4_values:
            for ctype in DpsClientType.types.keys():
                for dvg in tunnel_primary.DVG_Hash[ctype].values():
                    tunnel_primary.ip_add(dvg, False, ctype, socket.AF_INET, ip_value, DpsTransactionType.normal)
        ip6_values = tunnel_secondary.ip_listv6.ip_hash.keys()
        tunnel_secondary.ip_listv6.clear()
        for ip_value in ip6_values:
            for ctype in DpsClientType.types.keys():
                for dvg in tunnel_primary.DVG_Hash[ctype].values():
                    tunnel_primary.ip_add(dvg, False, ctype, socket.AF_INET, ip_value, DpsTransactionType.normal)
        #Delete the Secondary Tunnel
        tunnel_secondary.delete()
        return

    @staticmethod
    def register(domain, dvg, client_type, transaction_type, dps_client, pip_tuple_list):
        '''
        This routine should be called when a set of tunnel endpoint IP Addresses
        are registered by the DPS
        Client Protocol Handler.
        @param domain: The Domain object
        @type domain: Domain
        @param dvg: The DVG/VNID object
        @type dvg: DVG
        @param client_type: The Type of Client: should be in DpsClientType.types
        @type client_type: Integer 
        @param transaction_type: The Type of Transaction: should be in Domain.transaction_types
        @type transaction_type: Integer
        @param dps_client: The DPS Client associated with this Tunnel
        @type dps_client: DPSClient
        @type dps_client_port: Integer
        @param pip_tuple_list: A list of tuples of Physical IP Addresses, each 
                                tuple is of the form (inet_type, ip_value).
                                The inet_type = socket type i.e. AF_INET or AF_INET6
                                The ip_value = IPv4 in integer or IPv6 in string
        @type pip_tuple_list: List of tuples
        '''
        #Find if a tunnel exists with existing pIP
        if len(pip_tuple_list) == 0:
            return
        tunnel_set = {}
        if ((client_type == DpsClientType.dove_switch) or 
            (client_type == DpsClientType.vlan_gateway) or
            (client_type == DpsClientType.external_gateway)):
            for pip_tuple in pip_tuple_list:
                inet_type = pip_tuple[0]
                pip_value = pip_tuple[1]
                #ip_location = IPAddressLocation(inet_type, pip_value, 0)
                #print 'Tunnel Registration: VNID %s, IP %s\r'%(dvg.unique_id, ip_location.show_ip())
                if inet_type == socket.AF_INET:
                    ip_hash = domain.Tunnel_Endpoints_Hash_IPv4
                else:
                    ip_hash = domain.Tunnel_Endpoints_Hash_IPv6
                try:
                    tunnel = ip_hash[pip_value]
                    if tunnel.dps_client != dps_client:
                        message = 'Tunnel %s migrated from DPS Client %s to %s\r'%(tunnel.primary_ip().show_ip(),
                                                                                   tunnel.dps_client.location.show_ip(),
                                                                                   dps_client.location.show_ip())
                        dcslib.dps_data_write_log(DpsLogLevels.NOTICE, message)
                        #Delete the Tunnel IP since it no longer belongs with this
                        #Tunnel object
                        tunnel.ip_clear(inet_type, pip_value)
                        continue
                    tunnel_set[tunnel] = True
                except Exception:
                    continue
            if len(tunnel_set) > 1:
                #More than 1 tunnels found corresponding to the IP Addresses
                #Merge them into a single tunnel
                tunnels = tunnel_set.keys()
                tunnel_primary = tunnels[0]
                tunnels_secondary = tunnels[1:]
                for tunnel_secondary in tunnels_secondary:
                    print 'TunnelEndpoint.merge tunnel_primary %s, tunnel_secondary %s\r'%(tunnel_primary, tunnel_primary)
                    TunnelEndpoint.merge_tunnels(tunnel_primary, tunnel_secondary)
                tunnel = tunnel_primary
            elif len(tunnel_set) == 1:
                tunnel = tunnel_set.keys()[0]
            else:
                tunnel = None
            if tunnel is not None:
                tunnel.DVG_Hash[client_type][dvg.unique_id] = dvg
                for pip_tuple in pip_tuple_list:
                    inet_type = pip_tuple[0]
                    pip_value = pip_tuple[1]
                    tunnel.ip_add(dvg, False, client_type, inet_type, pip_value, transaction_type)
                DPSClientHost.Host_Add(domain, dps_client.location.inet_type, 
                                       dps_client.location.ip_value, dps_client.location.port, 
                                       client_type)
            else:
                #Allocate a new tunnel
                tunnel = TunnelEndpoint(True, domain, dvg, client_type, transaction_type, dps_client, pip_tuple_list)
            #if tunnel is not None:
            #    tunnel.show_details()
        if client_type == DpsClientType.external_gateway:
            for pip_tuple in pip_tuple_list:
                inet_type = pip_tuple[0]
                pip_value = pip_tuple[1]
                try:
                    if inet_type == socket.AF_INET:
                        IPList = dvg.ExternalGatewayIPListv4
                    else:
                        IPList = dvg.ExternalGatewayIPListv6
                    IPList.add(inet_type, pip_value)
                except Exception:
                    pass
        return

    @staticmethod
    def unregister(domain, dvg, client_type, pip_tuple_list):
        '''
        This routine should be called when a set of tunnel endpoint IP 
        Addresses are unregistered by the DPS
        Client Protocol Handler.
        @param domain: The Domain object
        @type domain: Domain
        @param dvg: The DVG/VNID object
        @type dvg: DVG
        @param client_type: The Type of Client: should be in DpsClientType.types
        @type client_type: Integer 
        @param pip_tuple_list: A list of tuples of Physical IP Addresses, each 
                                tuple is of the form (inet_type, ip_value).
                                The inet_type = socket type i.e. AF_INET or AF_INET6
                                The ip_value = IPv4 in integer or IPv6 in string
        @type pip_tuple_list: List of tuples
        '''
        #TODO: See if we need a DPS Client validation check
        if ((client_type == DpsClientType.dove_switch) or 
            (client_type == DpsClientType.vlan_gateway) or
            (client_type == DpsClientType.external_gateway)):
            for pip_tuple in pip_tuple_list:
                inet_type = pip_tuple[0]
                pip_value = pip_tuple[1]
                #Find the Tunnel from Domain Collection
                if inet_type == socket.AF_INET:
                    ip_hash = domain.Tunnel_Endpoints_Hash_IPv4
                else:
                    ip_hash = domain.Tunnel_Endpoints_Hash_IPv6
                try:
                    tunnel = ip_hash[pip_value]
                    try:
                        TunnelEndpoint.ip_delete(tunnel, dvg, client_type, inet_type, pip_value)
                        #tunnel.show_details()
                    except:
                        message = 'Tunnel.Unregister: Problem deleting IP %s'%pip_value
                        dcslib.dps_data_write_log(DpsLogLevels.WARNING, message)
                except Exception:
                    pass
        if client_type == DpsClientType.external_gateway:
            for pip_tuple in pip_tuple_list:
                inet_type = pip_tuple[0]
                pip_value = pip_tuple[1]
                try:
                    if inet_type == socket.AF_INET:
                        IPList = dvg.ExternalGatewayIPListv4
                    else:
                        IPList = dvg.ExternalGatewayIPListv6
                    IPList.remove(inet_type, pip_value)
                except Exception:
                    pass
        #TODO: Send update to all other Tunnels in Domain about this IP List unregister
        return

    def ip_tuple_list_get(self):
        '''
        Returns the List of IPs as IP Tuples
        @return - A list of tuples of Physical IP Addresses, each tuple is of 
                  the form (inet_type, ip_value).
                  The inet_type = socket type i.e. AF_INET or AF_INET6
                  The ip_value = IPv4 in integer or IPv6 in string
        @type pip_tuple_list: List of tuples
        '''
        ip_tuple_list = []
        for ip in self.ip_listv4.ip_list:
            ip_tuple_list.append((socket.AF_INET, ip))
        for ip in self.ip_listv6.ip_list:
            ip_tuple_list.append((socket.AF_INET6, ip))
        return ip_tuple_list

    def ip_list_get(self):
        '''
        Returns List of IPs as a string
        '''
        string_ipv4 = self.ip_listv4.toString()
        string_ipv4 = string_ipv4.rstrip()
        string_ipv4 = string_ipv4.rstrip(',')
        string_ipv6 = self.ip_listv6.toString()
        string_ipv6 = string_ipv6.rstrip()
        string_ipv6 = string_ipv6.rstrip(',')
        string_ip_list = string_ipv4 + ', ' + string_ipv6
        string_ip_list = string_ip_list.rstrip()
        string_ip_list = string_ip_list.rstrip(',')
        return string_ip_list

    def show(self):
        '''
        Display Contents of a Tunnel
        '''
        try:
            string_ip = 'Tunnel IPs [%s]'%(self.ip_list_get())
            string_info = 'DPS Client %s: Endpoints %s'%(self.dps_client.location.show(), len(self.Endpoint_Hash_MAC))
            print '%s [%s]\r'%(string_ip, string_info)
        except Exception:
            pass
        return

    def show_details_client_type(self, client_type):
        '''
        Display the details of a Tunnel given a client_type
        '''
        try:
            vnid_hash = self.DVG_Hash[client_type]
            vnid_hash_ip = self.VNID_Hash_IP[client_type]
            ip_hash_vnid = self.IP_Hash_VNID[client_type]
            client_type_string = DpsClientType.types[client_type]
            print 'Tunnel Type %s\r'%client_type_string
            print 'VNIDS %s\r'%vnid_hash.keys()
            for vnid, vnid_ips in vnid_hash_ip.items():
                ip_list = IPAddressList(socket.AF_INET)
                for vnid_ip in vnid_ips:
                    try:
                        ip_list.add(socket.AF_INET, vnid_ip)
                    except Exception:
                        pass
                print 'VNID %s, PIPv4s %s\r'%(vnid, ip_list.toString())
            for ip, ip_vnids in ip_hash_vnid.items():
                try:
                    ip_packed = struct.pack(IPAddressList.fmts[socket.AF_INET], ip)
                    ip_string = socket.inet_ntop(socket.AF_INET, ip_packed)
                except Exception:
                    pass
                print 'PIPv4 %s, VNIDs %s\r'%(ip_string, ip_vnids.keys())
        except Exception:
            pass
        return

    def show_details(self):
        '''
        Display the details of a Tunnel
        '''
        try:
            print '------------------------------------------------------------------\r'
            string_ip = 'Tunnel IPs [%s]'%(self.ip_list_get())
            string_info = '     DPS Client %s: Endpoint Count %s'%(self.dps_client.location.show(), len(self.Endpoint_Hash_MAC))
            print '%s\r'%string_ip
            print '%s\r'%string_info
            for client_type in DpsClientType.types.keys():
                client_type_string = DpsClientType.types[client_type]
                if len(self.DVG_Hash[client_type]) == 0:
                    if len(self.VNID_Hash_IP[client_type]) != 0:
                        print 'ALERT! self.VNID_Hash_IP for %s exists but no VNID in tunnel\r'%client_type_string
                    if len(self.IP_Hash_VNID[client_type]) != 0:
                        print 'ALERT! self.IP_Hash_VNID for %s exists but no VNID in tunnel\r'%client_type_string
                    continue
                self.show_details_client_type(client_type)
        except Exception, ex:
            pass
        print '------------------------------------------------------------------\r'
 def __init__(self, fregister, domain, dvg, client_type, transaction_type,
              dps_client, pip_tuple_list):
     '''
     Constructor:
     This routine assumes that the 1st IP address in the tuple uniquely
     identifies a DOVE Switch/VLAN Gateway within the Domain.
     @param fregister: Whether this is an explicit tunnel register
     @param fregister: Boolean
     @param domain: The Domain object
     @type domain: Domain
     @param dvg: The DVG/VNID object
     @type dvg: DVG
     @param client_type: The Type of Client: should be in DpsClientType.types
     @type client_type: Integer 
     @param transaction_type: The Type of Transaction: should be in Domain.transaction_types
     @type transaction_type: Integer
     @param dps_client: The DPS Client associated with this Tunnel
     @type dps_client: DPSClient
     @type dps_client_port: Integer
     @param pip_tuple_array: A list of tuples of Physical IP Addresses, each 
                             tuple is of the form (inet_type, ip_value).
                             The inet_type = socket type i.e. AF_INET or AF_INET6
                             The ip_value = IPv4 in integer or IPv6 in string
     @type pip_tuple_array: List of tuples
     '''
     if len(pip_tuple_list) == 0:
         raise Exception('No IP Address Provided: Invalid DOVE Switch')
     try:
         client_string = DpsClientType.types[client_type]
     except Exception:
         raise Exception('Not a supported Tunnel Type')
     self.domain = domain
     #DPS Client Location i.e. the UDP Port and Location
     self.dps_client = dps_client
     #############################################################
     #Based on Object Model Chapter 5.3: DOVE Switch
     #############################################################
     #TODO: SQL Table of Policies: Requirement 1.3
     #Hash List of all Endpoints hashed by MAC: Requirement 1.4
     self.Endpoint_Hash_MAC = {}
     #A dictionary indexed by VNID IDs, the value is the number
     #of Endpoints on that DOVE Switch in a particular VNID/DVG
     self.DVG_Hash = {}
     inet_type = pip_tuple_list[0][0]
     ip_value = pip_tuple_list[0][1]
     #ip_location = IPAddressLocation(inet_type, ip_value, 0)
     #print 'Tunnel %s created DVG_Hash\r'%ip_location.show_ip()
     for ctype in DpsClientType.types.keys():
         self.DVG_Hash[ctype] = {}
     #Key IP_value: Value VNID
     self.IP_Hash_VNID = {}
     #print 'Tunnel %s created IP_Hash_VNID\r'%ip_location.show_ip()
     for ctype in DpsClientType.types.keys():
         self.IP_Hash_VNID[ctype] = {}
     #Key VNID: Value Hash of IPs
     self.VNID_Hash_IP = {}
     for ctype in DpsClientType.types.keys():
         self.VNID_Hash_IP[ctype] = {}
     #print 'Tunnel %s created VNID_Hash_IP\r'%ip_location.show_ip()
     #List of Physical IP Addresses
     self.ip_listv4 = IPAddressList(socket.AF_INET)
     self.ip_listv6 = IPAddressList(socket.AF_INET6)
     for i in range(len(pip_tuple_list)):
         inet_type = pip_tuple_list[i][0]
         ip_value = pip_tuple_list[i][1]
         self.ip_add(dvg, fregister, client_type, inet_type, ip_value,
                     transaction_type)
     #############################################################
     #To be finished
     #############################################################
     #dcs_object.__init__(self, self.primary_ip().show())
     self.version = 0
     self.valid = True
     DPSClientHost.Host_Add(domain, dps_client.location.inet_type,
                            dps_client.location.ip_value,
                            dps_client.location.port, client_type)
class TunnelEndpoint:
    '''
    This represents a DOVE Underlay Tunnel in the DOVE environment -
    i.e DOVE Switch or VLAN Gateway.
    NOTE: Each Tunnel Endpoint will have multiple instances every every Domain
          it hosts Endpoints on. In other words if a TunnelEndpoint hosts
          endpoints on Domain A and Domain B, then there will be 2
          independent instances of that Tunnel Endpoint, 1 in Domain A and 1
          in Domain B.
    '''
    def __init__(self, fregister, domain, dvg, client_type, transaction_type,
                 dps_client, pip_tuple_list):
        '''
        Constructor:
        This routine assumes that the 1st IP address in the tuple uniquely
        identifies a DOVE Switch/VLAN Gateway within the Domain.
        @param fregister: Whether this is an explicit tunnel register
        @param fregister: Boolean
        @param domain: The Domain object
        @type domain: Domain
        @param dvg: The DVG/VNID object
        @type dvg: DVG
        @param client_type: The Type of Client: should be in DpsClientType.types
        @type client_type: Integer 
        @param transaction_type: The Type of Transaction: should be in Domain.transaction_types
        @type transaction_type: Integer
        @param dps_client: The DPS Client associated with this Tunnel
        @type dps_client: DPSClient
        @type dps_client_port: Integer
        @param pip_tuple_array: A list of tuples of Physical IP Addresses, each 
                                tuple is of the form (inet_type, ip_value).
                                The inet_type = socket type i.e. AF_INET or AF_INET6
                                The ip_value = IPv4 in integer or IPv6 in string
        @type pip_tuple_array: List of tuples
        '''
        if len(pip_tuple_list) == 0:
            raise Exception('No IP Address Provided: Invalid DOVE Switch')
        try:
            client_string = DpsClientType.types[client_type]
        except Exception:
            raise Exception('Not a supported Tunnel Type')
        self.domain = domain
        #DPS Client Location i.e. the UDP Port and Location
        self.dps_client = dps_client
        #############################################################
        #Based on Object Model Chapter 5.3: DOVE Switch
        #############################################################
        #TODO: SQL Table of Policies: Requirement 1.3
        #Hash List of all Endpoints hashed by MAC: Requirement 1.4
        self.Endpoint_Hash_MAC = {}
        #A dictionary indexed by VNID IDs, the value is the number
        #of Endpoints on that DOVE Switch in a particular VNID/DVG
        self.DVG_Hash = {}
        inet_type = pip_tuple_list[0][0]
        ip_value = pip_tuple_list[0][1]
        #ip_location = IPAddressLocation(inet_type, ip_value, 0)
        #print 'Tunnel %s created DVG_Hash\r'%ip_location.show_ip()
        for ctype in DpsClientType.types.keys():
            self.DVG_Hash[ctype] = {}
        #Key IP_value: Value VNID
        self.IP_Hash_VNID = {}
        #print 'Tunnel %s created IP_Hash_VNID\r'%ip_location.show_ip()
        for ctype in DpsClientType.types.keys():
            self.IP_Hash_VNID[ctype] = {}
        #Key VNID: Value Hash of IPs
        self.VNID_Hash_IP = {}
        for ctype in DpsClientType.types.keys():
            self.VNID_Hash_IP[ctype] = {}
        #print 'Tunnel %s created VNID_Hash_IP\r'%ip_location.show_ip()
        #List of Physical IP Addresses
        self.ip_listv4 = IPAddressList(socket.AF_INET)
        self.ip_listv6 = IPAddressList(socket.AF_INET6)
        for i in range(len(pip_tuple_list)):
            inet_type = pip_tuple_list[i][0]
            ip_value = pip_tuple_list[i][1]
            self.ip_add(dvg, fregister, client_type, inet_type, ip_value,
                        transaction_type)
        #############################################################
        #To be finished
        #############################################################
        #dcs_object.__init__(self, self.primary_ip().show())
        self.version = 0
        self.valid = True
        DPSClientHost.Host_Add(domain, dps_client.location.inet_type,
                               dps_client.location.ip_value,
                               dps_client.location.port, client_type)
        #print 'Tunnel %s created\r'%ip_location.show_ip()

    def endpoint_add(self, endpoint, transaction_type):
        '''
        Adds an Endpoint to the DOVE Tunnel
        @param transaction_type: The Type of Transaction: should be in Domain.transaction_types
        @type transaction_type: Integer
        '''
        #log.info('Tunnel.endpoint_add')
        #self.show(None)
        self.Endpoint_Hash_MAC[endpoint.vMac] = endpoint
        #self.show()
        return

    def endpoint_del(self, endpoint):
        '''
        Deletes an Endpoint from the DOVE Tunnel Endpoint
        '''
        try:
            del self.Endpoint_Hash_MAC[endpoint.vMac]
        except Exception:
            pass
        #self.show()
        if self.domain.unique_id == 0:
            #Remove the Tunnel Endpoint if no other Endpoints exist for Domain 0
            self.delete_if_empty()
        return

    def ip_add(self, dvg, fregister, client_type, inet_type, ip_value,
               transaction_type):
        '''
        This adds a tunnel IP address
        @param dvg: The DVG on which this registration occurred
        @type dvg: DVG
        @param fregister: Whether this is an explicit tunnel register
        @param fregister: Boolean
        @param client_type: The Type of Client: should be in DpsClientType.types
        @type client_type: Integer 
        @param inet_type: AF_INET or AF_INET6
        @type inet_type: Integer
        @param ip_value: The IP address value
        @type ip_value: Integer or String
        @param transaction_type: The Type of Transaction: should be in DpsTransactionType
        @type transaction_type: Integer
        '''
        while True:
            try:
                client_type_value = DpsClientType.types[client_type]
            except Exception:
                break
            self.DVG_Hash[client_type][dvg.unique_id] = dvg
            #Add to Tunnels List even though it may have come through other DVGs as well
            if inet_type == socket.AF_INET:
                if not self.ip_listv4.search(ip_value):
                    self.ip_listv4.add(inet_type, ip_value)
            elif inet_type == socket.AF_INET6:
                if not self.ip_listv4.search(ip_value):
                    self.ip_listv6.add(inet_type, ip_value)
            #log.info('ip_add: Adding to DPS Client %s', ip_value)
            #Add DVG to self.
            #Add IP to DPS Client
            DPSClient.tunnel_endpoint_add_IP(self.dps_client, self, inet_type,
                                             ip_value)
            #Add IP to this DVGs
            DVG.tunnel_endpoint_add_IP(dvg, fregister, self, client_type,
                                       inet_type, ip_value, transaction_type)
            try:
                vnid_hash_ip = self.VNID_Hash_IP[client_type][dvg.unique_id]
            except Exception:
                self.VNID_Hash_IP[client_type][dvg.unique_id] = {}
                vnid_hash_ip = self.VNID_Hash_IP[client_type][dvg.unique_id]
            vnid_hash_ip[ip_value] = True
            #Add DVGs to IP hash
            try:
                ip_hash_vnid = self.IP_Hash_VNID[client_type][ip_value]
            except Exception:
                self.IP_Hash_VNID[client_type][ip_value] = {}
                ip_hash_vnid = self.IP_Hash_VNID[client_type][ip_value]
            ip_hash_vnid[dvg.unique_id] = True
            #Add IP to Domain
            #log.info('ip_add: Adding to domain %s', self.domain.unique_id)
            Domain.tunnel_endpoint_add_IP(self.domain, self, inet_type,
                                          ip_value)
            break
        return

    def ip_delete(self, dvg, client_type, inet_type, ip_value):
        '''
        This deletes a tunnel IP address from a DVG and client type
        @param dvg: The DVG on which this registration occurred
        @type dvg: DVG
        @param client_type: The Type of Client: should be in DpsClientType.types
        @type client_type: Integer 
        @param inet_type: AF_INET or AF_INET6
        @type inet_type: Integer
        @param ip_value: The IP address value
        @type ip_value: Integer or String
        '''
        fdeleteVNID = False
        fdeleteIP = False
        while True:
            try:
                client_type_value = DpsClientType.types[client_type]
            except Exception:
                break
            try:
                vnid_hash_ip = self.VNID_Hash_IP[client_type][dvg.unique_id]
                del vnid_hash_ip[ip_value]
                if len(vnid_hash_ip) == 0:
                    del self.VNID_Hash_IP[client_type][dvg.unique_id]
                    fdeleteVNID = True
            except Exception:
                pass
            try:
                ip_hash_vnid = self.IP_Hash_VNID[client_type][ip_value]
                del ip_hash_vnid[dvg.unique_id]
                if len(ip_hash_vnid) == 0:
                    del self.IP_Hash_VNID[client_type][ip_value]
                    fdeleteIP = True
            except Exception:
                pass
            if fdeleteVNID:
                #Remove Tunnel from DVG
                DVG.tunnel_endpoint_delete(dvg, self, client_type)
                try:
                    del self.DVG_Hash[client_type][dvg.unique_id]
                    if len(self.DVG_Hash[client_type]) == 0:
                        #print 'Delete all Endpoints with client_type %s\r'%client_type_value
                        self.delete_client_type(client_type)
                except Exception:
                    pass
            if not fdeleteIP:
                break
            if fdeleteIP:
                #Remove only the IP from the DVG
                DVG.tunnel_endpoint_delete_IP(dvg, client_type, inet_type,
                                              ip_value)
            #Check if IP is present in any client type
            ip_present = False
            for ctype in self.IP_Hash_VNID.keys():
                try:
                    ip_hash_vnid = self.IP_Hash_VNID[ctype][ip_value]
                    ip_present = True
                    break
                except Exception:
                    continue
            if ip_present:
                break
            #Actually delete the IP from Domain and DPS Clients since no DVGs have it
            if inet_type == socket.AF_INET:
                self.ip_listv4.remove(inet_type, ip_value)
            elif inet_type == socket.AF_INET6:
                self.ip_listv6.remove(inet_type, ip_value)
            #Remove IP to DPS Client
            DPSClient.tunnel_endpoint_delete_IP(self.dps_client, inet_type,
                                                ip_value)
            #Remove IP from Domain
            Domain.tunnel_endpoint_delete_IP(self.domain, inet_type, ip_value)
            #Delete Self if not IP Addresses are present
            if self.ip_listv4.count() == 0 and self.ip_listv6.count() == 0:
                self.delete()
            break
        return

    def ip_clear(self, inet_type, ip_value):
        '''
        This deletes a tunnel IP address from this Tunnel and all DVGS and types
        @param dvg: The DVG on which this registration occurred
        @type dvg: DVG
        @param client_type: The Type of Client: should be in DpsClientType.types
        @type client_type: Integer 
        @param inet_type: AF_INET or AF_INET6
        @type inet_type: Integer
        @param ip_value: The IP address value
        @type ip_value: Integer or String
        '''
        while True:
            for client_type in DpsClientType.types.keys():
                #Delete IP from all matching VNIDs and Client Type
                for vnid in self.DVG_Hash[client_type].keys():
                    fRemoveVNID = False
                    try:
                        vnid_hash_ip = self.VNID_Hash_IP[client_type][vnid]
                        del vnid_hash_ip[ip_value]
                        if len(vnid_hash_ip) == 0:
                            del self.VNID_Hash_IP[client_type][vnid]
                            fRemoveVNID = True
                    except Exception:
                        pass
                    #Remove the IP from the DVG
                    try:
                        dvg = self.DVG_Hash[client_type][vnid]
                        DVG.tunnel_endpoint_delete_IP(dvg, client_type,
                                                      inet_type, ip_value)
                        if fRemoveVNID:
                            del self.DVG_Hash[client_type][vnid]
                            if len(self.DVG_Hash[client_type]) == 0:
                                #print 'Delete all Endpoints with client_type %s\r'%client_type
                                self.delete_client_type(client_type)
                    except Exception:
                        pass
                #Delete IP completly from Tunnel
                try:
                    ip_hash_vnid = self.IP_Hash_VNID[client_type][ip_value]
                    ip_hash_vnid.clear()
                    del self.IP_Hash_VNID[client_type][ip_value]
                except Exception:
                    pass
            #Delete the IP from Domain and DPS Clients since no DVGs have it
            if inet_type == socket.AF_INET:
                self.ip_listv4.remove(inet_type, ip_value)
            elif inet_type == socket.AF_INET6:
                self.ip_listv6.remove(inet_type, ip_value)
            #Remove IP to DPS Client
            DPSClient.tunnel_endpoint_delete_IP(self.dps_client, inet_type,
                                                ip_value)
            #Remove IP from Domain
            Domain.tunnel_endpoint_delete_IP(self.domain, inet_type, ip_value)
            #Delete Self if not IP Addresses are present
            if self.ip_listv4.count() == 0 and self.ip_listv6.count() == 0:
                self.delete()
            break
        return

    def delete_if_empty(self):
        '''
        This routine checks if a DPS Client no longer hosts any Endpoint.
        If it doesn't, it unlinks itself from all the domain
        '''
        if len(self.Endpoint_Hash_MAC) != 0:
            return
        if not self.valid:
            return
        self.valid = False
        #Remove self from all DVGs
        for client_type in DpsClientType.types.keys():
            for dvg in self.DVG_Hash[client_type].values():
                DVG.tunnel_endpoint_delete(dvg, self, client_type)
        #Clear the VNID/DVG Hash
        self.DVG_Hash.clear()
        #Remove from DPS Client Collection
        DPSClient.tunnel_endpoint_delete(self.dps_client, self)
        #Remove from Domain Collection
        Domain.tunnel_endpoint_delete(self.domain, self)
        #Clear IPs
        self.ip_listv4.clear()
        self.ip_listv6.clear()
        return

    def delete(self):
        '''
        Destructor:
        '''
        #Lose references to all endpoint objects
        for endpoint in self.Endpoint_Hash_MAC.values():
            endpoint.delete()
        self.Endpoint_Hash_MAC.clear()
        #Now call delete_if_empty
        self.delete_if_empty()
        return

    def delete_client_type(self, client_type):
        '''
        Remove association with a particular client type
        '''
        for endpoint_key in self.Endpoint_Hash_MAC.keys():
            try:
                endpoint = self.Endpoint_Hash_MAC[endpoint_key]
            except Exception:
                continue
            if endpoint.client_type == client_type:
                endpoint.delete()
        return

    def primary_ip(self):
        '''
        This routine shows any one IP Address to represent the Tunnel
        '''
        try:
            ip = self.ip_listv4.get_primary()
            return IPAddressLocation(socket.AF_INET, ip, 0)
        except Exception:
            pass
        try:
            ip = self.ip_listv6.get_primary()
            return IPAddressLocation(socket.AF_INET6, ip, 0)
        except Exception:
            pass
        return IPAddressLocation(socket.AF_INET, 0, 0)

    def tunnel_types_supported(self):
        '''
        This routine lists the tunnel type hosted by this tunnel
        '''
        tunnel_types = []
        for tunnel_type in DpsClientType.types.keys():
            try:
                dvg_hash = self.DVG_Hash[tunnel_type]
                if len(dvg_hash) == 0:
                    continue
                tunnel_types.append(tunnel_type)
            except Exception:
                pass
        return tunnel_types

    @staticmethod
    def merge_tunnels(tunnel_primary, tunnel_secondary):
        '''
        This routine merges the content of secondary tunnel into the primary tunnel
        and deletes the secondary tunnel
        '''
        #Copy Endpoints
        tunnel_primary.Endpoint_Hash_MAC = dict(
            tunnel_primary.Endpoint_Hash_MAC.items() +
            tunnel_secondary.Endpoint_Hash_MAC.items())
        tunnel_secondary.Endpoint_Hash_MAC.clear()
        #Copy DVGs
        for ctype in DpsClientType.types.keys():
            tunnel_primary.DVG_Hash[ctype] = dict(
                tunnel_primary.DVG_Hash[ctype].items() +
                tunnel_secondary.DVG_Hash[ctype].items())
            tunnel_secondary.DVG_Hash[ctype].clear()
        #Copy
        for ctype in DpsClientType.types.keys():
            tunnel_primary.IP_Hash_VNID[ctype] = dict(
                tunnel_primary.IP_Hash_VNID[ctype].items() +
                tunnel_secondary.IP_Hash_VNID[ctype].items())
            tunnel_secondary.IP_Hash_VNID[ctype].clear()
        #Key VNID: Value Hash of IPs
        for ctype in DpsClientType.types.keys():
            tunnel_primary.VNID_Hash_IP[ctype] = dict(
                tunnel_primary.VNID_Hash_IP[ctype].items() +
                tunnel_secondary.VNID_Hash_IP[ctype].items())
            tunnel_secondary.VNID_Hash_IP[ctype].clear()
        #List of Physical IP Addresses
        ipv4_values = tunnel_secondary.ip_listv4.ip_hash.keys()
        tunnel_secondary.ip_listv4.clear()
        for ip_value in ipv4_values:
            for ctype in DpsClientType.types.keys():
                for dvg in tunnel_primary.DVG_Hash[ctype].values():
                    tunnel_primary.ip_add(dvg, False, ctype, socket.AF_INET,
                                          ip_value, DpsTransactionType.normal)
        ip6_values = tunnel_secondary.ip_listv6.ip_hash.keys()
        tunnel_secondary.ip_listv6.clear()
        for ip_value in ip6_values:
            for ctype in DpsClientType.types.keys():
                for dvg in tunnel_primary.DVG_Hash[ctype].values():
                    tunnel_primary.ip_add(dvg, False, ctype, socket.AF_INET,
                                          ip_value, DpsTransactionType.normal)
        #Delete the Secondary Tunnel
        tunnel_secondary.delete()
        return

    @staticmethod
    def register(domain, dvg, client_type, transaction_type, dps_client,
                 pip_tuple_list):
        '''
        This routine should be called when a set of tunnel endpoint IP Addresses
        are registered by the DPS
        Client Protocol Handler.
        @param domain: The Domain object
        @type domain: Domain
        @param dvg: The DVG/VNID object
        @type dvg: DVG
        @param client_type: The Type of Client: should be in DpsClientType.types
        @type client_type: Integer 
        @param transaction_type: The Type of Transaction: should be in Domain.transaction_types
        @type transaction_type: Integer
        @param dps_client: The DPS Client associated with this Tunnel
        @type dps_client: DPSClient
        @type dps_client_port: Integer
        @param pip_tuple_list: A list of tuples of Physical IP Addresses, each 
                                tuple is of the form (inet_type, ip_value).
                                The inet_type = socket type i.e. AF_INET or AF_INET6
                                The ip_value = IPv4 in integer or IPv6 in string
        @type pip_tuple_list: List of tuples
        '''
        #Find if a tunnel exists with existing pIP
        if len(pip_tuple_list) == 0:
            return
        tunnel_set = {}
        if ((client_type == DpsClientType.dove_switch)
                or (client_type == DpsClientType.vlan_gateway)
                or (client_type == DpsClientType.external_gateway)):
            for pip_tuple in pip_tuple_list:
                inet_type = pip_tuple[0]
                pip_value = pip_tuple[1]
                #ip_location = IPAddressLocation(inet_type, pip_value, 0)
                #print 'Tunnel Registration: VNID %s, IP %s\r'%(dvg.unique_id, ip_location.show_ip())
                if inet_type == socket.AF_INET:
                    ip_hash = domain.Tunnel_Endpoints_Hash_IPv4
                else:
                    ip_hash = domain.Tunnel_Endpoints_Hash_IPv6
                try:
                    tunnel = ip_hash[pip_value]
                    if tunnel.dps_client != dps_client:
                        message = 'Tunnel %s migrated from DPS Client %s to %s\r' % (
                            tunnel.primary_ip().show_ip(),
                            tunnel.dps_client.location.show_ip(),
                            dps_client.location.show_ip())
                        dcslib.dps_data_write_log(DpsLogLevels.NOTICE, message)
                        #Delete the Tunnel IP since it no longer belongs with this
                        #Tunnel object
                        tunnel.ip_clear(inet_type, pip_value)
                        continue
                    tunnel_set[tunnel] = True
                except Exception:
                    continue
            if len(tunnel_set) > 1:
                #More than 1 tunnels found corresponding to the IP Addresses
                #Merge them into a single tunnel
                tunnels = tunnel_set.keys()
                tunnel_primary = tunnels[0]
                tunnels_secondary = tunnels[1:]
                for tunnel_secondary in tunnels_secondary:
                    print 'TunnelEndpoint.merge tunnel_primary %s, tunnel_secondary %s\r' % (
                        tunnel_primary, tunnel_primary)
                    TunnelEndpoint.merge_tunnels(tunnel_primary,
                                                 tunnel_secondary)
                tunnel = tunnel_primary
            elif len(tunnel_set) == 1:
                tunnel = tunnel_set.keys()[0]
            else:
                tunnel = None
            if tunnel is not None:
                tunnel.DVG_Hash[client_type][dvg.unique_id] = dvg
                for pip_tuple in pip_tuple_list:
                    inet_type = pip_tuple[0]
                    pip_value = pip_tuple[1]
                    tunnel.ip_add(dvg, False, client_type, inet_type,
                                  pip_value, transaction_type)
                DPSClientHost.Host_Add(domain, dps_client.location.inet_type,
                                       dps_client.location.ip_value,
                                       dps_client.location.port, client_type)
            else:
                #Allocate a new tunnel
                tunnel = TunnelEndpoint(True, domain, dvg, client_type,
                                        transaction_type, dps_client,
                                        pip_tuple_list)
            #if tunnel is not None:
            #    tunnel.show_details()
        if client_type == DpsClientType.external_gateway:
            for pip_tuple in pip_tuple_list:
                inet_type = pip_tuple[0]
                pip_value = pip_tuple[1]
                try:
                    if inet_type == socket.AF_INET:
                        IPList = dvg.ExternalGatewayIPListv4
                    else:
                        IPList = dvg.ExternalGatewayIPListv6
                    IPList.add(inet_type, pip_value)
                except Exception:
                    pass
        return

    @staticmethod
    def unregister(domain, dvg, client_type, pip_tuple_list):
        '''
        This routine should be called when a set of tunnel endpoint IP 
        Addresses are unregistered by the DPS
        Client Protocol Handler.
        @param domain: The Domain object
        @type domain: Domain
        @param dvg: The DVG/VNID object
        @type dvg: DVG
        @param client_type: The Type of Client: should be in DpsClientType.types
        @type client_type: Integer 
        @param pip_tuple_list: A list of tuples of Physical IP Addresses, each 
                                tuple is of the form (inet_type, ip_value).
                                The inet_type = socket type i.e. AF_INET or AF_INET6
                                The ip_value = IPv4 in integer or IPv6 in string
        @type pip_tuple_list: List of tuples
        '''
        #TODO: See if we need a DPS Client validation check
        if ((client_type == DpsClientType.dove_switch)
                or (client_type == DpsClientType.vlan_gateway)
                or (client_type == DpsClientType.external_gateway)):
            for pip_tuple in pip_tuple_list:
                inet_type = pip_tuple[0]
                pip_value = pip_tuple[1]
                #Find the Tunnel from Domain Collection
                if inet_type == socket.AF_INET:
                    ip_hash = domain.Tunnel_Endpoints_Hash_IPv4
                else:
                    ip_hash = domain.Tunnel_Endpoints_Hash_IPv6
                try:
                    tunnel = ip_hash[pip_value]
                    try:
                        TunnelEndpoint.ip_delete(tunnel, dvg, client_type,
                                                 inet_type, pip_value)
                        #tunnel.show_details()
                    except:
                        message = 'Tunnel.Unregister: Problem deleting IP %s' % pip_value
                        dcslib.dps_data_write_log(DpsLogLevels.WARNING,
                                                  message)
                except Exception:
                    pass
        if client_type == DpsClientType.external_gateway:
            for pip_tuple in pip_tuple_list:
                inet_type = pip_tuple[0]
                pip_value = pip_tuple[1]
                try:
                    if inet_type == socket.AF_INET:
                        IPList = dvg.ExternalGatewayIPListv4
                    else:
                        IPList = dvg.ExternalGatewayIPListv6
                    IPList.remove(inet_type, pip_value)
                except Exception:
                    pass
        #TODO: Send update to all other Tunnels in Domain about this IP List unregister
        return

    def ip_tuple_list_get(self):
        '''
        Returns the List of IPs as IP Tuples
        @return - A list of tuples of Physical IP Addresses, each tuple is of 
                  the form (inet_type, ip_value).
                  The inet_type = socket type i.e. AF_INET or AF_INET6
                  The ip_value = IPv4 in integer or IPv6 in string
        @type pip_tuple_list: List of tuples
        '''
        ip_tuple_list = []
        for ip in self.ip_listv4.ip_list:
            ip_tuple_list.append((socket.AF_INET, ip))
        for ip in self.ip_listv6.ip_list:
            ip_tuple_list.append((socket.AF_INET6, ip))
        return ip_tuple_list

    def ip_list_get(self):
        '''
        Returns List of IPs as a string
        '''
        string_ipv4 = self.ip_listv4.toString()
        string_ipv4 = string_ipv4.rstrip()
        string_ipv4 = string_ipv4.rstrip(',')
        string_ipv6 = self.ip_listv6.toString()
        string_ipv6 = string_ipv6.rstrip()
        string_ipv6 = string_ipv6.rstrip(',')
        string_ip_list = string_ipv4 + ', ' + string_ipv6
        string_ip_list = string_ip_list.rstrip()
        string_ip_list = string_ip_list.rstrip(',')
        return string_ip_list

    def show(self):
        '''
        Display Contents of a Tunnel
        '''
        try:
            string_ip = 'Tunnel IPs [%s]' % (self.ip_list_get())
            string_info = 'DPS Client %s: Endpoints %s' % (
                self.dps_client.location.show(), len(self.Endpoint_Hash_MAC))
            print '%s [%s]\r' % (string_ip, string_info)
        except Exception:
            pass
        return

    def show_details_client_type(self, client_type):
        '''
        Display the details of a Tunnel given a client_type
        '''
        try:
            vnid_hash = self.DVG_Hash[client_type]
            vnid_hash_ip = self.VNID_Hash_IP[client_type]
            ip_hash_vnid = self.IP_Hash_VNID[client_type]
            client_type_string = DpsClientType.types[client_type]
            print 'Tunnel Type %s\r' % client_type_string
            print 'VNIDS %s\r' % vnid_hash.keys()
            for vnid, vnid_ips in vnid_hash_ip.items():
                ip_list = IPAddressList(socket.AF_INET)
                for vnid_ip in vnid_ips:
                    try:
                        ip_list.add(socket.AF_INET, vnid_ip)
                    except Exception:
                        pass
                print 'VNID %s, PIPv4s %s\r' % (vnid, ip_list.toString())
            for ip, ip_vnids in ip_hash_vnid.items():
                try:
                    ip_packed = struct.pack(IPAddressList.fmts[socket.AF_INET],
                                            ip)
                    ip_string = socket.inet_ntop(socket.AF_INET, ip_packed)
                except Exception:
                    pass
                print 'PIPv4 %s, VNIDs %s\r' % (ip_string, ip_vnids.keys())
        except Exception:
            pass
        return

    def show_details(self):
        '''
        Display the details of a Tunnel
        '''
        try:
            print '------------------------------------------------------------------\r'
            string_ip = 'Tunnel IPs [%s]' % (self.ip_list_get())
            string_info = '     DPS Client %s: Endpoint Count %s' % (
                self.dps_client.location.show(), len(self.Endpoint_Hash_MAC))
            print '%s\r' % string_ip
            print '%s\r' % string_info
            for client_type in DpsClientType.types.keys():
                client_type_string = DpsClientType.types[client_type]
                if len(self.DVG_Hash[client_type]) == 0:
                    if len(self.VNID_Hash_IP[client_type]) != 0:
                        print 'ALERT! self.VNID_Hash_IP for %s exists but no VNID in tunnel\r' % client_type_string
                    if len(self.IP_Hash_VNID[client_type]) != 0:
                        print 'ALERT! self.IP_Hash_VNID for %s exists but no VNID in tunnel\r' % client_type_string
                    continue
                self.show_details_client_type(client_type)
        except Exception, ex:
            pass
        print '------------------------------------------------------------------\r'
Beispiel #7
0
    def __init__(self, domain_id, active):
        '''
        Constructor:
        @param domain_id: The Domain ID
        @type domain_id: Integer
        @param active: Whether the Domain is active
        @type active: Boolean
        '''
        if domain_id < 0 or domain_id > 16777215:
            raise Exception ('Domain ID %s not valid'%(domain_id))
        self.IP_Subnet_List = IPSubnetList()
        self.active = active
        self.replication_factor = 1
        self.mass_transfer = None
        #Set of nodes to forward updates after Mass Transfer is complete
        #and waiting for all other nodes to see this new DPS Node
        #as part of the domain.
        self.mass_transfer_forward_nodes = {}
        #Create Timer for the Domain Object
        #Create the Replication Dictionary
        #The Replication dictionary
        self.replication_query_id_server = {}
        self.replication_query_id_client = {}
        #Based on Object Model Chapter 5.1: Domain Object
        #Collection of DVGs hashed by DVG id.
        #TODO: Add to Domain Object in Domain Object Model
        self.DVG_Hash = {}
        #############################################################
        #Endpoint Object Tables (Requirement 1.1 and 1.2)
        #############################################################
        #Endpoint Object Hash Table (IP Address)
        #Separating IPv4 and IPv6 into different Hashes since one
        #will be hashed by integer, the other string
        self.Endpoint_Hash_IPv4 = {}
        self.Endpoint_Hash_IPv6 = {}
        #Endpoint Object Hash Table (MAC Address)
        self.Endpoint_Hash_MAC = {}
        #############################################################
        #Policy Object Hash Table (Requirement 1.2)
        #The first index is for unicast policy, the second for multicast
        #############################################################
        self.Policy_Hash_DVG = [{}, {}]
        #############################################################
        #DPS Client Hash Tables (Requirement 1.5)
        #############################################################
        #This is to store the DPS Client IPs Address (Different from 
        #the DOVE Switch/Gateway IP address)
        self.DPSClients_Hash_IPv4 = {}
        self.DPSClients_Hash_IPv6 = {}
        #This is to store the Tunnel Endpoint IP Address
        self.Tunnel_Endpoints_Hash_IPv4 = {}
        self.Tunnel_Endpoints_Hash_IPv6 = {}
        #List of Implicit Gateway IP Address for this Domain
        self.ImplicitGatewayIPListv4 = IPAddressList(socket.AF_INET)
        self.ImplicitGatewayIPListv6 = IPAddressList(socket.AF_INET6)
        #Multicast Object
        self.Multicast = Multicast(self, domain_id)
        #Address Resolution
        self.AddressResolution = AddressResolution(domain_id)
        self.ConflictDetection = ConflictDetection(domain_id)
        #############################################################
        #Add the domain into DPS Collection Hash Table
        #############################################################
        DpsCollection.Domain_Hash[domain_id] = self
        #DpsCollection.VNID_Hash[domain_id] = domain_id
        #############################################################
        #Statistics 
        #############################################################
        self.Stats_Array = []
        curr_time = time.time()
        self.Stats_Array.append([curr_time, 0, 0, 0])

        self.Endpoint_Update_Count = 0
        self.Endpoint_Update_Count_Delta = 0
        self.Endpoint_Lookup_Count = 0
        self.Endpoint_Lookup_Count_Delta = 0
        self.Policy_Lookup_Count = 0
        self.Policy_Lookup_Count_Delta = 0
        self.Multicast_Lookup_Count = 0
        self.Internal_Gateway_Lookup_Count = 0
        #############################################################
        #To be finished
        #############################################################
        # Initialize the common part
        dcs_object.__init__(self, domain_id)
Beispiel #8
0
class Domain(dcs_object):
    '''
    This represents the Domain Object in DOVE
    '''

    def __init__(self, domain_id, active):
        '''
        Constructor:
        @param domain_id: The Domain ID
        @type domain_id: Integer
        @param active: Whether the Domain is active
        @type active: Boolean
        '''
        if domain_id < 0 or domain_id > 16777215:
            raise Exception ('Domain ID %s not valid'%(domain_id))
        self.IP_Subnet_List = IPSubnetList()
        self.active = active
        self.replication_factor = 1
        self.mass_transfer = None
        #Set of nodes to forward updates after Mass Transfer is complete
        #and waiting for all other nodes to see this new DPS Node
        #as part of the domain.
        self.mass_transfer_forward_nodes = {}
        #Create Timer for the Domain Object
        #Create the Replication Dictionary
        #The Replication dictionary
        self.replication_query_id_server = {}
        self.replication_query_id_client = {}
        #Based on Object Model Chapter 5.1: Domain Object
        #Collection of DVGs hashed by DVG id.
        #TODO: Add to Domain Object in Domain Object Model
        self.DVG_Hash = {}
        #############################################################
        #Endpoint Object Tables (Requirement 1.1 and 1.2)
        #############################################################
        #Endpoint Object Hash Table (IP Address)
        #Separating IPv4 and IPv6 into different Hashes since one
        #will be hashed by integer, the other string
        self.Endpoint_Hash_IPv4 = {}
        self.Endpoint_Hash_IPv6 = {}
        #Endpoint Object Hash Table (MAC Address)
        self.Endpoint_Hash_MAC = {}
        #############################################################
        #Policy Object Hash Table (Requirement 1.2)
        #The first index is for unicast policy, the second for multicast
        #############################################################
        self.Policy_Hash_DVG = [{}, {}]
        #############################################################
        #DPS Client Hash Tables (Requirement 1.5)
        #############################################################
        #This is to store the DPS Client IPs Address (Different from 
        #the DOVE Switch/Gateway IP address)
        self.DPSClients_Hash_IPv4 = {}
        self.DPSClients_Hash_IPv6 = {}
        #This is to store the Tunnel Endpoint IP Address
        self.Tunnel_Endpoints_Hash_IPv4 = {}
        self.Tunnel_Endpoints_Hash_IPv6 = {}
        #List of Implicit Gateway IP Address for this Domain
        self.ImplicitGatewayIPListv4 = IPAddressList(socket.AF_INET)
        self.ImplicitGatewayIPListv6 = IPAddressList(socket.AF_INET6)
        #Multicast Object
        self.Multicast = Multicast(self, domain_id)
        #Address Resolution
        self.AddressResolution = AddressResolution(domain_id)
        self.ConflictDetection = ConflictDetection(domain_id)
        #############################################################
        #Add the domain into DPS Collection Hash Table
        #############################################################
        DpsCollection.Domain_Hash[domain_id] = self
        #DpsCollection.VNID_Hash[domain_id] = domain_id
        #############################################################
        #Statistics 
        #############################################################
        self.Stats_Array = []
        curr_time = time.time()
        self.Stats_Array.append([curr_time, 0, 0, 0])

        self.Endpoint_Update_Count = 0
        self.Endpoint_Update_Count_Delta = 0
        self.Endpoint_Lookup_Count = 0
        self.Endpoint_Lookup_Count_Delta = 0
        self.Policy_Lookup_Count = 0
        self.Policy_Lookup_Count_Delta = 0
        self.Multicast_Lookup_Count = 0
        self.Internal_Gateway_Lookup_Count = 0
        #############################################################
        #To be finished
        #############################################################
        # Initialize the common part
        dcs_object.__init__(self, domain_id)

    def dvg_add(self, dvg):
        '''
        Adds a DVG to the Domain Collection
        @param dvg: The DVG Object
        @type dvg: DVG
        '''
        self.DVG_Hash[dvg.unique_id] = dvg
        return

    def dvg_del(self, dvg):
        '''
        Deletes a DVG to the Domain Collection
        @param dvg: The DVG Object
        @type dvg: DVG
        '''
        #Remove VNID from AddressResolution
        self.AddressResolution.vnid_delete(dvg)
        try:
            dvg = self.DVG_Hash[dvg.unique_id]
            del self.DVG_Hash[dvg.unique_id]
            dvg.delete()
        except Exception:
            pass
        return

    def vnid_random_get(self):
        '''
        This routine gets a random (active) VNID in a domain
        '''
        try:
            vnid = self.DVG_Hash.keys()[0]
        except Exception:
            vnid = 0
        return vnid

    def policy_add(self, policy):
        '''
        Adds a Policy to the Domain Collection
        @param dvg: The Policy Object
        @type dvg: Policy
        '''
        self.Policy_Hash_DVG[policy.traffic_type][policy.key] = policy
        return

    def policy_del(self, policy):
        '''
        Deletes a DVG to the Domain Collection
        @param dvg: The Policy Object
        @type dvg: Policy
        '''
        try:
            del self.Policy_Hash_DVG[policy.traffic_type][policy.key]
        except Exception:
            pass
        return

    def endpoint_add(self, endpoint):
        '''
        Adds an Endpoint to the Domain Collection
        @param endpoint: Endpoint Object
        @type endpoint: Endpoint
        '''
        self.Endpoint_Hash_MAC[endpoint.vMac] = endpoint
        for vIP_key in endpoint.vIP_set.keys():
            self.endpoint_vIP_add(endpoint, endpoint.vIP_set[vIP_key])
        return

    def endpoint_del(self, endpoint):
        '''
        Removes an Endpoint from the Domain Collection
        @param endpoint: Endpoint Object
        @type endpoint: Endpoint
        '''
        try:
            del self.Endpoint_Hash_MAC[endpoint.vMac]
        except Exception:
            pass
        for vIP_key in endpoint.vIP_set.keys():
            self.endpoint_vIP_del(endpoint.vIP_set[vIP_key])
        return

    def endpoint_vIP_add(self, endpoint, vIP):
        '''
        Adds an Endpoint (Virtual) IP Address to the collection
        @param endpoint: Endpoint Object
        @type endpoint: Endpoint
        @param vIP: IP Address
        @type vIP: IPAddressLocation
        '''
        if vIP.inet_type == socket.AF_INET:
            ip_hash = self.Endpoint_Hash_IPv4
        else:
            ip_hash = self.Endpoint_Hash_IPv6
        ip_hash[vIP.ip_value] = endpoint
        return

    def endpoint_vIP_del(self, vIP):
        '''
        Deletes an Endpoint (Virtual) IP Address from the Domain collection
        @param vIP: IP Address
        @type vIP: IPAddressLocation
        '''
        if vIP.inet_type == socket.AF_INET:
            ip_hash = self.Endpoint_Hash_IPv4
        else:
            ip_hash = self.Endpoint_Hash_IPv6
        try:
            del ip_hash[vIP.ip_value]
        except Exception:
            pass
        return

    def tunnel_endpoint_add(self, tunnel_endpoint):
        '''
        Adds a Tunnel Endpoint to the Domain Collection
        @param tunnel_endpoint: The Tunnel Endpoint
        @type tunnel_endpoint: TunnelEndpoint Object
        '''
        for ip_value in tunnel_endpoint.ip_listv4.ip_list:
            ip_hash = self.Tunnel_Endpoints_Hash_IPv4
            ip_hash[ip_value] = tunnel_endpoint
        for ip_value in tunnel_endpoint.ip_listv6.ip_list:
            ip_hash = self.Tunnel_Endpoints_Hash_IPv6
            ip_hash[ip_value] = tunnel_endpoint
        return

    def tunnel_endpoint_delete(self, tunnel_endpoint):
        '''
        Deletes a Tunnel Endpoint from the Domain Collection
        @param tunnel_endpoint: The Tunnel Endpoint
        @type tunnel_endpoint: TunnelEndpoint Object
        '''
        for ip_value in tunnel_endpoint.ip_listv4.ip_list:
            ip_hash = self.Tunnel_Endpoints_Hash_IPv4
            try:
                del ip_hash[ip_value]
            except Exception:
                pass
        for ip_value in tunnel_endpoint.ip_listv6.ip_list:
            ip_hash = self.Tunnel_Endpoints_Hash_IPv6
            try:
                del ip_hash[ip_value]
            except Exception:
                pass
        return

    def tunnel_endpoint_add_IP(self, tunnel_endpoint, inet_type, ip_value):
        '''
        Adds a Tunnel Endpoint Physical IP Address to the Domain Collection
        @param tunnel_endpoint: The Tunnel Endpoint
        @type tunnel_endpoint: TunnelEndpoint Object
        @param inet_type: AF_INET or AF_INET6
        @type inet_type: Integer
        @param ip_value: The IP address value
        @type ip_value: Integer or String
        '''
        #TODO: Should we add all IPs to this hash or only the primary IP
        if inet_type == socket.AF_INET:
            ip_hash = self.Tunnel_Endpoints_Hash_IPv4
        else:
            ip_hash = self.Tunnel_Endpoints_Hash_IPv6
        ip_hash[ip_value] = tunnel_endpoint
        return

    def tunnel_endpoint_delete_IP(self, inet_type, ip_value):
        '''
        Deletes a Tunnel Endpoint Physical IP Address from the Domain Collection.
        @param inet_type: AF_INET or AF_INET6
        @type inet_type: Integer
        @param ip_value: The IP address value
        @type ip_value: Integer or String
        '''
        if inet_type == socket.AF_INET:
            ip_hash = self.Tunnel_Endpoints_Hash_IPv4
        else:
            ip_hash = self.Tunnel_Endpoints_Hash_IPv6
        try:
            del ip_hash[ip_value]
        except Exception:
            pass
        return

    def dps_client_add(self, dps_client):
        '''
        Adds a DPS Client to the collection
        @param dps_client: The DPS Client
        @type dps_client: DpsClient Object
        '''
        if dps_client.location.inet_type == socket.AF_INET:
            ip_hash = self.DPSClients_Hash_IPv4
        else:
            ip_hash = self.DPSClients_Hash_IPv6
        ip_hash[dps_client.location.ip_value] = dps_client
        return

    def dps_client_delete(self, dps_client):
        '''
        Deletes a DPS Client from the collection
        @param dps_client: The DPS Client
        @type dps_client: DpsClient Object
        '''
        #Remove DPS Client from AddressResolution
        self.AddressResolution.dps_client_delete(dps_client)
        if dps_client.location.inet_type == socket.AF_INET:
            ip_hash = self.DPSClients_Hash_IPv4
        else:
            ip_hash = self.DPSClients_Hash_IPv6
        try:
            del ip_hash[dps_client.location.ip_value]
        except Exception:
            pass
        return

    def delete(self, fdelete):
        '''
        Deletes the objects from all the Hash Tables
        @param fdelete: True if the Domain has been deleted from DOVE
        @type fdelete: Boolean
        '''
        if not self.valid:
            return
        self.valid = False
        #Unlink from DPS Clients
        DPSClientHost.Domain_Deleted_Locally(self)
        #Unlink from Address_Resolution_Requests
        try:
            del DpsCollection.Address_Resolution_Requests[self.unique_id]
        except Exception:
            pass
        #Unlink self from DpsCollection
        try:
            del DpsCollection.Domain_Hash[self.unique_id]
        except Exception:
            pass
        #Delete all DVGs
        if fdelete:
            #Only delete dvg structures if the domain is deleted
            for dvg in self.DVG_Hash.values():
                try:
                    dvg.delete()
                except Exception:
                    pass
            #Delete all endpoints
            for endpoint in self.Endpoint_Hash_MAC.values():
                try:
                    endpoint.delete()
                except Exception:
                    pass
            for endpoint in self.Endpoint_Hash_IPv4.values():
                try:
                    endpoint.delete()
                except Exception:
                    pass
            for endpoint in self.Endpoint_Hash_IPv6.values():
                try:
                    endpoint.delete()
                except Exception:
                    pass
            for tunnel in self.Tunnel_Endpoints_Hash_IPv4.values():
                try:
                    tunnel.delete()
                except Exception:
                    pass
            for tunnel in self.Tunnel_Endpoints_Hash_IPv6.values():
                try:
                    tunnel.delete()
                except Exception:
                    pass
            for dps_client in self.DPSClients_Hash_IPv4.values():
                try:
                    dps_client.delete()
                except Exception:
                    pass
            for dps_client in self.DPSClients_Hash_IPv6.values():
                try:
                    dps_client.delete()
                except Exception:
                    pass
            #Delete all policies
            for policy in self.Policy_Hash_DVG[0].values():
                try:
                    policy.delete()
                except Exception:
                    pass
            for policy in self.Policy_Hash_DVG[1].values():
                try:
                    policy.delete()
                except Exception:
                    pass
        self.DVG_Hash.clear()
        self.Endpoint_Hash_MAC.clear()
        self.Endpoint_Hash_IPv4.clear()
        self.Endpoint_Hash_IPv6.clear()
        #Delete all tunnels
        self.Tunnel_Endpoints_Hash_IPv4.clear()
        self.Tunnel_Endpoints_Hash_IPv6.clear()
        #Delete all dps clients
        self.DPSClients_Hash_IPv4.clear()
        self.DPSClients_Hash_IPv6.clear()
        self.Policy_Hash_DVG[0].clear()
        self.Policy_Hash_DVG[1].clear()
        #Destroy IP subnet list
        self.IP_Subnet_List.destroy()
        #Destroy Address Resolution
        self.AddressResolution.delete()
        #Destroy Conflict Detection
        self.ConflictDetection.delete()
        #Destroy Multicast
        self.Multicast.delete()
        return

    def ip_subnet_add(self, ip_value, mask_value, gateway, mode):
        '''
        Adds a IP Subnet to List
        @param ip_value: IP Address of Subnet
        @type ip_value: Integer
        @param mask_value: Mask of Subnet
        @type mask_value: Integer
        @param gateway: Gateway of Subnet
        @type gateway: Integer
        @param mode: Mode of Subnet
        @type mode: Integer (0 = Dedicated, 1 = Shared)
        @return: The status of the operation
        @rtype: dove_status (defined in include/status.h) Integer
        '''
        ret_val = self.IP_Subnet_List.add(ip_value, mask_value, gateway, mode)
        if ret_val == DOVEStatus.DOVE_STATUS_OK:
            #Add to implicit gateway collection
            self.ImplicitGatewayIPListv4.add(socket.AF_INET, gateway)
        return ret_val

    def ip_subnet_delete(self, ip_value, mask_value):
        '''
        Deletes a IP Subnet from List
        @param ip_value: IP Address of Subnet
        @type ip_value: Integer
        @param mask_value: Mask of Subnet
        @type mask_value: Integer
        @return: The status of the operation
        @rtype: dove_status (defined in include/status.h) Integer
        '''
        while True:
            #Get the gateway associated with this subnet
            ret_val, subnet_ip, subnet_mask, subnet_mode, subnet_gateway = self.ip_subnet_get(ip_value, mask_value)
            if ret_val != DOVEStatus.DOVE_STATUS_OK:
                break
            #Remove the gateway from the Implicit Gateway collection
            self.ImplicitGatewayIPListv4.remove(socket.AF_INET, subnet_gateway)
            #Remove the Subnet
            ret_val = self.IP_Subnet_List.delete(ip_value, mask_value)
            break
        return ret_val

    def ip_subnet_lookup(self, ip_value):
        '''
        Check if a given IP falls into a subnet in the list and get the subnet
        @param ip_value: IP Address
        @type ip_value: Integer
        @return: status, subnet_ip, subnet_mask, subnet_mode, subnet_gateway
        @rtype: Integer, Integer, Integer, Integer, Integer
        '''
        return self.IP_Subnet_List.lookup(ip_value)

    def ip_subnet_get(self, ip_value, mask_value):
        '''
        Get a exact subnet according to IP and Mask pair
        @param ip_value: IP Address
        @type ip_value: Integer
        @param mask_value: Mask of Subnet
        @type mask_value: Integer
        @return: status, subnet_ip, subnet_mask, subnet_mode, subnet_gateway
        @rtype: Integer, Integer, Integer, Integer, Integer
        '''
        return self.IP_Subnet_List.get(ip_value, mask_value)

    def ip_subnet_show(self):
        '''
        List all IP Subnets from List
        @return: The status of the operation
        @rtype: dove_status (defined in include/status.h) Integer
        '''
        return self.IP_Subnet_List.show()

    def ip_subnet_flush(self):
        '''
        Flush all IP Subnets from List
        @return: The status of the operation
        @rtype: dove_status (defined in include/status.h) Integer
        '''
        return self.IP_Subnet_List.flush()

    def process_lookup_not_found(self, dps_client_IP_type, dps_client_IP_val,
                                 source_dvg, vIP_type, vIP_value, vIP_packed):
        '''
        This routine handles the case of vIP lookup failure in the list of Endpoints
        in a domain. The client protocol handler sends out the External Gateway
        as the answer, but in the background this routine checks with all relevant
        DPS Client in every VNID in this domain to resolve the Address
        @param dps_client_IP_type: socket.AF_INET6 or socket.AF_INET
        @type dps_client_IP_type: Integer
        @param dps_client_IP_val: socket.AF_INET6 or socket.AF_INET
        @type dps_client_IP_val: Integer
        @param source_dvg: The Source VNID
        @type source_dvg: DVG
        @param vIP_type: socket.AF_INET or socket.AF_INET6
        @type vIP_type: Integer
        @param vIP_val: IPv6 or IPv4 Address
        @type vIP_val: String or Integer
        @param vIP_packed: vIP packed
        @type vIP_packed: ByteArray
        '''
        if not self.valid:
            return
        if ((self.AddressResolution.total >= self.AddressResolution.total_max) or 
            (len(self.AddressResolution.endpoint_resolution) >= self.AddressResolution.vIP_not_found_max)):
            return
        while True:
            try:
                if dps_client_IP_type == socket.AF_INET:
                    dps_client = self.DPSClients_Hash_IPv4[dps_client_IP_val]
                else:
                    dps_client = self.DPSClients_Hash_IPv6[dps_client_IP_val]
            except Exception:
                break
            #Store in Address Resolution Structure
            fSendAddressResolution = self.AddressResolution.process_lookup_not_found(dps_client, source_dvg, vIP_type, vIP_value)
            #Queue Work Item to Send Address Resolution Queries
            if fSendAddressResolution:
                DpsCollection.address_resolution_queue.put((self.send_resolution_work, (vIP_value, vIP_packed)))
            break
        return

    def send_resolution_work(self, vIP_tuple):
        '''
        This routine sends address resolution queries to all dps clients in all DVGs
        @attention: Do not call this routine with global lock held
        @param vIP_tuple: (vIP_value, vIP_packed)
        @type vIP_tuple: Tuple of (String or Integer, ByteArray)
        '''
        #log.warning('send_resolution_work: Enter\r')
        vIP_value = vIP_tuple[0]
        vIP_packed = vIP_tuple[1]
        DpsCollection.global_lock.acquire()
        while True:
            if not self.valid:
                break
            try:
                dvg_list = self.DVG_Hash.values()
            except Exception:
                dvg_list = []
            #Send Address Resolution to all DVGS
            #Drop Lock in between DVGs to allow other threads to run
            DpsCollection.global_lock.release()
            for dvg in dvg_list:
                DpsCollection.global_lock.acquire()
                try:
                    ret_val, subnet_ip, subnet_mask, subnet_mode, subnet_gateway = dvg.ip_subnet_lookup(vIP_value)
                    if ret_val == DOVEStatus.DOVE_STATUS_OK:
                        dvg.send_address_resolution(vIP_packed)
                except Exception:
                    pass
                DpsCollection.global_lock.release()
            DpsCollection.global_lock.acquire()
            #Store self in Global Timer
            DpsCollection.Address_Resolution_Requests[self.unique_id] = self
            break
        DpsCollection.global_lock.release()
        #log.warning('send_resolution_work: Exit\r')
        return

    def mass_transfer_finish(self, dps_location, fcomplete, weight):
        '''
        This routine will be called by the Mass Transfer Callback when mass transfer
        of data to remote node is done.
        @param dps_location: The location of the remote node
        @type dps_location: IPAddressLocation
        @param fcomplete: Indicates if the transfer was complete or had to be cancelled
                          due to some issue
        @type fcomplete: False
        @param weight: The weight of the mass transfer
        @type weight: Integer
        '''
        message = 'Domain %d: Mass Transfer finished to %s, completed %s'%(self.unique_id,
                                                                           dps_location.show_ip(),
                                                                           fcomplete)
        dcslib.dps_cluster_write_log(DpsLogLevels.INFO, message)
        mass_transfer_complete = False
        DpsCollection.global_lock.acquire()
        while True:
            try:
                if self.mass_transfer is None:
                    break
                #Don't make self.mass_transfer None till activate has been exchanged
                #self.mass_transfer = None
                DpsCollection.mass_transfer_lock.acquire()
                try:
                    DpsCollection.MassTransfer_Active -= weight
                    if DpsCollection.MassTransfer_Active < 0:
                        message = 'Domain %s: Mass Transfer finished, accounting problem with mass transfer count %s'
                        dcslib.dps_cluster_write_log(DpsLogLevels.CRITICAL, message)
                except Exception:
                    pass
                DpsCollection.mass_transfer_lock.release()
                if fcomplete and self.valid:
                    self.mass_transfer_forward_nodes[dps_location.ip_value] = dps_location
                    mass_transfer_complete = True
            except Exception:
                pass
            break
        DpsCollection.global_lock.release()
        if mass_transfer_complete:
            message = 'Domain %s: Mass Transfer Complete, sending Activate message to remote Node %s'%(self.unique_id, 
                                                                                                       dps_location.show_ip())
            dcslib.dps_cluster_write_log(DpsLogLevels.NOTICE, message)
            ret = dcslib.dps_domain_activate_on_node(dps_location.ip_value_packed, 
                                                     self.unique_id, 
                                                     self.replication_factor)
            if ret != 0:
                message = 'Domain %s: Activate on Node %s failed, clearing local forwarding cache'%(self.unique_id, 
                                                                                                    dps_location.show_ip())
                dcslib.dps_cluster_write_log(DpsLogLevels.NOTICE, message)
                try:
                    del self.mass_transfer_forward_nodes[dps_location.ip_value]
                except Exception:
                    pass
        else:
            message = 'Domain %s: Mass Transfer canceled, sending Deactivate message to remote Node %s'%(self.unique_id, 
                                                                                                         dps_location.show_ip())
            dcslib.dps_cluster_write_log(DpsLogLevels.NOTICE, message)
            ret = dcslib.dps_domain_deactivate_on_node(dps_location.ip_value_packed, 
                                                       self.unique_id)
            if ret != 0:
                message = 'Domain %s: Deactivate on Node %s Failed'%(self.unique_id,
                                                                     dps_location.show_ip())
                dcslib.dps_cluster_write_log(DpsLogLevels.NOTICE, message)
        DpsCollection.global_lock.acquire()
        self.mass_transfer = None
        DpsCollection.global_lock.release()
        return

    def mass_transfer_processing(self):
        '''
        This routine determines if the local node is in the midst of mass
        transfer processing
        @return - True if mass transfer is underway
        @rtype - Boolean
        '''
        if self.mass_transfer is not None or len(self.mass_transfer_forward_nodes) > 0:
            return True
        else:
            return False

    def send_vm_migration_update_to(self, dps_client, endpoint, vnid, query_id):
        if not self.active:
            return
        if query_id == 0:
            query_id_use = DpsCollection.generate_query_id()
        else:
            query_id_use = query_id
        # to send to dcslib.send_all_vm_migration_update ()
        vipv4_list = []
        vipv6_list = []
        pipv4_list = endpoint.tunnel_endpoint.ip_listv4.ip_list[:]
        pipv6_list = endpoint.tunnel_endpoint.ip_listv6.ip_list[:]
        for vIP_obj in endpoint.vIP_set.values():
            if vIP_obj.fValid:
                if vIP_obj.inet_type == socket.AF_INET:
                    vipv4_list.append(vIP_obj.ip_value)
                elif vIP_obj.inet_type == socket.AF_INET6:
                    vipv6_list.append(vIP_obj.ip_value)
        ret_val = dcslib.send_all_vm_migration_update(dps_client.location.ip_value_packed, #DPS Client Location IP
                                                      dps_client.location.port, #DPS Client Port
                                                      vnid, #VNID ID
                                                      query_id_use,
                                                      endpoint.dvg.unique_id,
                                                      endpoint.version,
                                                      pipv4_list,
                                                      pipv6_list,
                                                      endpoint.vMac,
                                                      vipv4_list,
                                                      vipv6_list)
        if ret_val != 0: 
            message = 'send_all_vm_migration_update FAILED with value %d'%(ret_val)
            dcslib.dps_data_write_log(DpsLogLevels.NOTICE, message)
        return

    def send_vm_migration_update(self, endpoint, vnid):
        '''
        This routine is used to send a vm migration update to all the DPS clients
        handling the domain.
        '''
        if not self.active:
            return
        DpsCollection.global_lock.acquire()
        #Create a set of dps_clients
        dps_clients = {}
        for dps_client in self.DPSClients_Hash_IPv4.values():
            dps_clients[dps_client] = True
        for dps_client in self.DPSClients_Hash_IPv6.values():
            dps_clients[dps_client] = True
        for dps_client in dps_clients.keys():
            self.send_vm_migration_update_to(dps_client, endpoint, vnid, 0)
        dps_clients.clear()
        DpsCollection.global_lock.release()
        return

    def show(self, fdetails):
        '''
        Display Contents of a Domain
        @param fdetails: Whether to show detailed information
        @type fdetails: Integer (0 = False, 1 = True)
        '''
        print '------------------------------------------------------------------\r'
        print 'Showing Domain: %s\r'%(self.unique_id)
        #############################################################
        #Show list of DVGs.
        #############################################################
        dvg_list = ''
        for dvg in self.DVG_Hash.values():
            dvg_list += str(dvg.unique_id) + ', '
        dvg_list = dvg_list.rstrip()
        dvg_list = dvg_list.rstrip(',')
        print 'VNIDs: [%s]\r'%(dvg_list)
        ##############################################################
        ##Show number of DPS Clients
        ##############################################################
        dps_client_count = len(self.DPSClients_Hash_IPv4) + len(self.DPSClients_Hash_IPv6)
        if fdetails and dps_client_count > 0:
            print '------------------------- DPS Clients ----------------------------\r'
            for dps_clients in self.DPSClients_Hash_IPv4.values():
                dps_clients.show()
            for dps_clients in self.DPSClients_Hash_IPv6.values():
                dps_clients.show()
            print '------------------------------------------------------------------\r'
        else:
            print 'DPS Clients: Total %s\r'%dps_client_count
        # #############################################################
        # #Show number of tunnels.
        # #############################################################
        # tunnel_count = len(self.Tunnel_Endpoints_Hash_IPv4)+ len(self.Tunnel_Endpoints_Hash_IPv6)
        # if fdetails and tunnel_count > 0:
        #     tunnel_set = {}
        #     for tunnel in self.Tunnel_Endpoints_Hash_IPv4.values():
        #         tunnel_set[tunnel] = True
        #     for tunnel in self.Tunnel_Endpoints_Hash_IPv6.values():
        #         tunnel_set[tunnel] = True
        #     print '---------------------- Tunnel Endpoints --------------------------\r'
        #     for tunnel in tunnel_set.keys():
        #         tunnel.show_details()
        #     tunnel_set.clear()
        #     print '------------------------------------------------------------------\r'
        # else:
        #     print 'Tunnels: Total %s\r'%tunnel_count
        #############################################################
        #Show number of endpoints.
        #############################################################
        endpoint_count = len(self.Endpoint_Hash_MAC)
        if fdetails and endpoint_count > 0:
            print '-------------------------- Endpoints -----------------------------\r'
            for endpoint in self.Endpoint_Hash_MAC.values():
                endpoint.show()
        else:
            print 'Endpoints: Total %s\r'%endpoint_count
            endpoint_ip = len(self.Endpoint_Hash_IPv4) + len(self.Endpoint_Hash_IPv6)
            print 'Endpoints: Total Number of vIP Addresses %s\r'%endpoint_ip
        #############################################################
        #Show Implicit Gateways.
        #############################################################
        count = len(self.ImplicitGatewayIPListv4.ip_hash) + len(self.ImplicitGatewayIPListv6.ip_hash)
        if fdetails and count > 0:
            print '------------------------- Implicit Gateways ----------------------\r'
            if len(self.ImplicitGatewayIPListv4.ip_hash) > 0:
                self.ImplicitGatewayIPListv4.show()
            if len(self.ImplicitGatewayIPListv6.ip_hash) > 0:
                self.ImplicitGatewayIPListv6.show()
        else:
            print 'Implicit Gateways: Total %s\r'%count
        ##############################################################
        ##Show Dedicated Subnet Lists
        ##############################################################
        if self.IP_Subnet_List.count > 0:
            print 'Subnet List: Total %s\r'%self.IP_Subnet_List.count
            self.ip_subnet_show()
        #############################################################
        #Show Policies.
        #############################################################
        count = len(self.Policy_Hash_DVG[0])
        if fdetails and count > 0:
            print '----------------------- Unicast Policies -------------------------\r'
            for policy in self.Policy_Hash_DVG[0].values():
                if policy.src_dvg == policy.dst_dvg and policy.action_connectivity == policy.action_forward:
                    continue
                print '%s\r'%policy.show()
        else:
            print 'Policy Count %s\r'%count
        #############################################################
        #Show Nodes to whom requests are being forwarded and
        #Mass Transfer
        #############################################################
        if self.mass_transfer is not None:
            print '\r'
            print 'Ongoing mass transfer to %s\r'%self.mass_transfer.remote_location.show()
        if len(self.mass_transfer_forward_nodes) > 0:
            for remote_location in self.mass_transfer_forward_nodes.values():
                print 'Forwarding Requests to DPS Node %s\r'%remote_location.show()
        return

    def show_mass_transfer(self):
        '''
        '''
        if self.mass_transfer is not None:
            print '\r'
            print 'Ongoing mass transfer to %s, Stage %s\n'%(self.mass_transfer.remote_location.show_ip(),
                                                             self.mass_transfer.stage_get())
            self.mass_transfer.show()
        if len(self.mass_transfer_forward_nodes) > 0:
            for remote_location in self.mass_transfer_forward_nodes.values():
                print 'Forwarding Requests to DPS Node %s\r'%remote_location.show()
        return
Beispiel #9
0
    def __init__(self, domain_id, active):
        '''
        Constructor:
        @param domain_id: The Domain ID
        @type domain_id: Integer
        @param active: Whether the Domain is active
        @type active: Boolean
        '''
        if domain_id < 0 or domain_id > 16777215:
            raise Exception('Domain ID %s not valid' % (domain_id))
        self.IP_Subnet_List = IPSubnetList()
        self.active = active
        self.replication_factor = 1
        self.mass_transfer = None
        #Set of nodes to forward updates after Mass Transfer is complete
        #and waiting for all other nodes to see this new DPS Node
        #as part of the domain.
        self.mass_transfer_forward_nodes = {}
        #Create Timer for the Domain Object
        #Create the Replication Dictionary
        #The Replication dictionary
        self.replication_query_id_server = {}
        self.replication_query_id_client = {}
        #Based on Object Model Chapter 5.1: Domain Object
        #Collection of DVGs hashed by DVG id.
        #TODO: Add to Domain Object in Domain Object Model
        self.DVG_Hash = {}
        #############################################################
        #Endpoint Object Tables (Requirement 1.1 and 1.2)
        #############################################################
        #Endpoint Object Hash Table (IP Address)
        #Separating IPv4 and IPv6 into different Hashes since one
        #will be hashed by integer, the other string
        self.Endpoint_Hash_IPv4 = {}
        self.Endpoint_Hash_IPv6 = {}
        #Endpoint Object Hash Table (MAC Address)
        self.Endpoint_Hash_MAC = {}
        #############################################################
        #Policy Object Hash Table (Requirement 1.2)
        #The first index is for unicast policy, the second for multicast
        #############################################################
        self.Policy_Hash_DVG = [{}, {}]
        #############################################################
        #DPS Client Hash Tables (Requirement 1.5)
        #############################################################
        #This is to store the DPS Client IPs Address (Different from
        #the DOVE Switch/Gateway IP address)
        self.DPSClients_Hash_IPv4 = {}
        self.DPSClients_Hash_IPv6 = {}
        #This is to store the Tunnel Endpoint IP Address
        self.Tunnel_Endpoints_Hash_IPv4 = {}
        self.Tunnel_Endpoints_Hash_IPv6 = {}
        #List of Implicit Gateway IP Address for this Domain
        self.ImplicitGatewayIPListv4 = IPAddressList(socket.AF_INET)
        self.ImplicitGatewayIPListv6 = IPAddressList(socket.AF_INET6)
        #Multicast Object
        self.Multicast = Multicast(self, domain_id)
        #Address Resolution
        self.AddressResolution = AddressResolution(domain_id)
        self.ConflictDetection = ConflictDetection(domain_id)
        #############################################################
        #Add the domain into DPS Collection Hash Table
        #############################################################
        DpsCollection.Domain_Hash[domain_id] = self
        #DpsCollection.VNID_Hash[domain_id] = domain_id
        #############################################################
        #Statistics
        #############################################################
        self.Stats_Array = []
        curr_time = time.time()
        self.Stats_Array.append([curr_time, 0, 0, 0])

        self.Endpoint_Update_Count = 0
        self.Endpoint_Update_Count_Delta = 0
        self.Endpoint_Lookup_Count = 0
        self.Endpoint_Lookup_Count_Delta = 0
        self.Policy_Lookup_Count = 0
        self.Policy_Lookup_Count_Delta = 0
        self.Multicast_Lookup_Count = 0
        self.Internal_Gateway_Lookup_Count = 0
        #############################################################
        #To be finished
        #############################################################
        # Initialize the common part
        dcs_object.__init__(self, domain_id)
Beispiel #10
0
class Domain(dcs_object):
    '''
    This represents the Domain Object in DOVE
    '''
    def __init__(self, domain_id, active):
        '''
        Constructor:
        @param domain_id: The Domain ID
        @type domain_id: Integer
        @param active: Whether the Domain is active
        @type active: Boolean
        '''
        if domain_id < 0 or domain_id > 16777215:
            raise Exception('Domain ID %s not valid' % (domain_id))
        self.IP_Subnet_List = IPSubnetList()
        self.active = active
        self.replication_factor = 1
        self.mass_transfer = None
        #Set of nodes to forward updates after Mass Transfer is complete
        #and waiting for all other nodes to see this new DPS Node
        #as part of the domain.
        self.mass_transfer_forward_nodes = {}
        #Create Timer for the Domain Object
        #Create the Replication Dictionary
        #The Replication dictionary
        self.replication_query_id_server = {}
        self.replication_query_id_client = {}
        #Based on Object Model Chapter 5.1: Domain Object
        #Collection of DVGs hashed by DVG id.
        #TODO: Add to Domain Object in Domain Object Model
        self.DVG_Hash = {}
        #############################################################
        #Endpoint Object Tables (Requirement 1.1 and 1.2)
        #############################################################
        #Endpoint Object Hash Table (IP Address)
        #Separating IPv4 and IPv6 into different Hashes since one
        #will be hashed by integer, the other string
        self.Endpoint_Hash_IPv4 = {}
        self.Endpoint_Hash_IPv6 = {}
        #Endpoint Object Hash Table (MAC Address)
        self.Endpoint_Hash_MAC = {}
        #############################################################
        #Policy Object Hash Table (Requirement 1.2)
        #The first index is for unicast policy, the second for multicast
        #############################################################
        self.Policy_Hash_DVG = [{}, {}]
        #############################################################
        #DPS Client Hash Tables (Requirement 1.5)
        #############################################################
        #This is to store the DPS Client IPs Address (Different from
        #the DOVE Switch/Gateway IP address)
        self.DPSClients_Hash_IPv4 = {}
        self.DPSClients_Hash_IPv6 = {}
        #This is to store the Tunnel Endpoint IP Address
        self.Tunnel_Endpoints_Hash_IPv4 = {}
        self.Tunnel_Endpoints_Hash_IPv6 = {}
        #List of Implicit Gateway IP Address for this Domain
        self.ImplicitGatewayIPListv4 = IPAddressList(socket.AF_INET)
        self.ImplicitGatewayIPListv6 = IPAddressList(socket.AF_INET6)
        #Multicast Object
        self.Multicast = Multicast(self, domain_id)
        #Address Resolution
        self.AddressResolution = AddressResolution(domain_id)
        self.ConflictDetection = ConflictDetection(domain_id)
        #############################################################
        #Add the domain into DPS Collection Hash Table
        #############################################################
        DpsCollection.Domain_Hash[domain_id] = self
        #DpsCollection.VNID_Hash[domain_id] = domain_id
        #############################################################
        #Statistics
        #############################################################
        self.Stats_Array = []
        curr_time = time.time()
        self.Stats_Array.append([curr_time, 0, 0, 0])

        self.Endpoint_Update_Count = 0
        self.Endpoint_Update_Count_Delta = 0
        self.Endpoint_Lookup_Count = 0
        self.Endpoint_Lookup_Count_Delta = 0
        self.Policy_Lookup_Count = 0
        self.Policy_Lookup_Count_Delta = 0
        self.Multicast_Lookup_Count = 0
        self.Internal_Gateway_Lookup_Count = 0
        #############################################################
        #To be finished
        #############################################################
        # Initialize the common part
        dcs_object.__init__(self, domain_id)

    def dvg_add(self, dvg):
        '''
        Adds a DVG to the Domain Collection
        @param dvg: The DVG Object
        @type dvg: DVG
        '''
        self.DVG_Hash[dvg.unique_id] = dvg
        return

    def dvg_del(self, dvg):
        '''
        Deletes a DVG to the Domain Collection
        @param dvg: The DVG Object
        @type dvg: DVG
        '''
        #Remove VNID from AddressResolution
        self.AddressResolution.vnid_delete(dvg)
        try:
            dvg = self.DVG_Hash[dvg.unique_id]
            del self.DVG_Hash[dvg.unique_id]
            dvg.delete()
        except Exception:
            pass
        return

    def vnid_random_get(self):
        '''
        This routine gets a random (active) VNID in a domain
        '''
        try:
            vnid = self.DVG_Hash.keys()[0]
        except Exception:
            vnid = 0
        return vnid

    def policy_add(self, policy):
        '''
        Adds a Policy to the Domain Collection
        @param dvg: The Policy Object
        @type dvg: Policy
        '''
        self.Policy_Hash_DVG[policy.traffic_type][policy.key] = policy
        return

    def policy_del(self, policy):
        '''
        Deletes a DVG to the Domain Collection
        @param dvg: The Policy Object
        @type dvg: Policy
        '''
        try:
            del self.Policy_Hash_DVG[policy.traffic_type][policy.key]
        except Exception:
            pass
        return

    def endpoint_add(self, endpoint):
        '''
        Adds an Endpoint to the Domain Collection
        @param endpoint: Endpoint Object
        @type endpoint: Endpoint
        '''
        self.Endpoint_Hash_MAC[endpoint.vMac] = endpoint
        for vIP_key in endpoint.vIP_set.keys():
            self.endpoint_vIP_add(endpoint, endpoint.vIP_set[vIP_key])
        return

    def endpoint_del(self, endpoint):
        '''
        Removes an Endpoint from the Domain Collection
        @param endpoint: Endpoint Object
        @type endpoint: Endpoint
        '''
        try:
            del self.Endpoint_Hash_MAC[endpoint.vMac]
        except Exception:
            pass
        for vIP_key in endpoint.vIP_set.keys():
            self.endpoint_vIP_del(endpoint.vIP_set[vIP_key])
        return

    def endpoint_vIP_add(self, endpoint, vIP):
        '''
        Adds an Endpoint (Virtual) IP Address to the collection
        @param endpoint: Endpoint Object
        @type endpoint: Endpoint
        @param vIP: IP Address
        @type vIP: IPAddressLocation
        '''
        if vIP.inet_type == socket.AF_INET:
            ip_hash = self.Endpoint_Hash_IPv4
        else:
            ip_hash = self.Endpoint_Hash_IPv6
        ip_hash[vIP.ip_value] = endpoint
        return

    def endpoint_vIP_del(self, vIP):
        '''
        Deletes an Endpoint (Virtual) IP Address from the Domain collection
        @param vIP: IP Address
        @type vIP: IPAddressLocation
        '''
        if vIP.inet_type == socket.AF_INET:
            ip_hash = self.Endpoint_Hash_IPv4
        else:
            ip_hash = self.Endpoint_Hash_IPv6
        try:
            del ip_hash[vIP.ip_value]
        except Exception:
            pass
        return

    def tunnel_endpoint_add(self, tunnel_endpoint):
        '''
        Adds a Tunnel Endpoint to the Domain Collection
        @param tunnel_endpoint: The Tunnel Endpoint
        @type tunnel_endpoint: TunnelEndpoint Object
        '''
        for ip_value in tunnel_endpoint.ip_listv4.ip_list:
            ip_hash = self.Tunnel_Endpoints_Hash_IPv4
            ip_hash[ip_value] = tunnel_endpoint
        for ip_value in tunnel_endpoint.ip_listv6.ip_list:
            ip_hash = self.Tunnel_Endpoints_Hash_IPv6
            ip_hash[ip_value] = tunnel_endpoint
        return

    def tunnel_endpoint_delete(self, tunnel_endpoint):
        '''
        Deletes a Tunnel Endpoint from the Domain Collection
        @param tunnel_endpoint: The Tunnel Endpoint
        @type tunnel_endpoint: TunnelEndpoint Object
        '''
        for ip_value in tunnel_endpoint.ip_listv4.ip_list:
            ip_hash = self.Tunnel_Endpoints_Hash_IPv4
            try:
                del ip_hash[ip_value]
            except Exception:
                pass
        for ip_value in tunnel_endpoint.ip_listv6.ip_list:
            ip_hash = self.Tunnel_Endpoints_Hash_IPv6
            try:
                del ip_hash[ip_value]
            except Exception:
                pass
        return

    def tunnel_endpoint_add_IP(self, tunnel_endpoint, inet_type, ip_value):
        '''
        Adds a Tunnel Endpoint Physical IP Address to the Domain Collection
        @param tunnel_endpoint: The Tunnel Endpoint
        @type tunnel_endpoint: TunnelEndpoint Object
        @param inet_type: AF_INET or AF_INET6
        @type inet_type: Integer
        @param ip_value: The IP address value
        @type ip_value: Integer or String
        '''
        #TODO: Should we add all IPs to this hash or only the primary IP
        if inet_type == socket.AF_INET:
            ip_hash = self.Tunnel_Endpoints_Hash_IPv4
        else:
            ip_hash = self.Tunnel_Endpoints_Hash_IPv6
        ip_hash[ip_value] = tunnel_endpoint
        return

    def tunnel_endpoint_delete_IP(self, inet_type, ip_value):
        '''
        Deletes a Tunnel Endpoint Physical IP Address from the Domain Collection.
        @param inet_type: AF_INET or AF_INET6
        @type inet_type: Integer
        @param ip_value: The IP address value
        @type ip_value: Integer or String
        '''
        if inet_type == socket.AF_INET:
            ip_hash = self.Tunnel_Endpoints_Hash_IPv4
        else:
            ip_hash = self.Tunnel_Endpoints_Hash_IPv6
        try:
            del ip_hash[ip_value]
        except Exception:
            pass
        return

    def dps_client_add(self, dps_client):
        '''
        Adds a DPS Client to the collection
        @param dps_client: The DPS Client
        @type dps_client: DpsClient Object
        '''
        if dps_client.location.inet_type == socket.AF_INET:
            ip_hash = self.DPSClients_Hash_IPv4
        else:
            ip_hash = self.DPSClients_Hash_IPv6
        ip_hash[dps_client.location.ip_value] = dps_client
        return

    def dps_client_delete(self, dps_client):
        '''
        Deletes a DPS Client from the collection
        @param dps_client: The DPS Client
        @type dps_client: DpsClient Object
        '''
        #Remove DPS Client from AddressResolution
        self.AddressResolution.dps_client_delete(dps_client)
        if dps_client.location.inet_type == socket.AF_INET:
            ip_hash = self.DPSClients_Hash_IPv4
        else:
            ip_hash = self.DPSClients_Hash_IPv6
        try:
            del ip_hash[dps_client.location.ip_value]
        except Exception:
            pass
        return

    def delete(self, fdelete):
        '''
        Deletes the objects from all the Hash Tables
        @param fdelete: True if the Domain has been deleted from DOVE
        @type fdelete: Boolean
        '''
        if not self.valid:
            return
        self.valid = False
        #Unlink from DPS Clients
        DPSClientHost.Domain_Deleted_Locally(self)
        #Unlink from Address_Resolution_Requests
        try:
            del DpsCollection.Address_Resolution_Requests[self.unique_id]
        except Exception:
            pass
        #Unlink self from DpsCollection
        try:
            del DpsCollection.Domain_Hash[self.unique_id]
        except Exception:
            pass
        #Delete all DVGs
        if fdelete:
            #Only delete dvg structures if the domain is deleted
            for dvg in self.DVG_Hash.values():
                try:
                    dvg.delete()
                except Exception:
                    pass
            #Delete all endpoints
            for endpoint in self.Endpoint_Hash_MAC.values():
                try:
                    endpoint.delete()
                except Exception:
                    pass
            for endpoint in self.Endpoint_Hash_IPv4.values():
                try:
                    endpoint.delete()
                except Exception:
                    pass
            for endpoint in self.Endpoint_Hash_IPv6.values():
                try:
                    endpoint.delete()
                except Exception:
                    pass
            for tunnel in self.Tunnel_Endpoints_Hash_IPv4.values():
                try:
                    tunnel.delete()
                except Exception:
                    pass
            for tunnel in self.Tunnel_Endpoints_Hash_IPv6.values():
                try:
                    tunnel.delete()
                except Exception:
                    pass
            for dps_client in self.DPSClients_Hash_IPv4.values():
                try:
                    dps_client.delete()
                except Exception:
                    pass
            for dps_client in self.DPSClients_Hash_IPv6.values():
                try:
                    dps_client.delete()
                except Exception:
                    pass
            #Delete all policies
            for policy in self.Policy_Hash_DVG[0].values():
                try:
                    policy.delete()
                except Exception:
                    pass
            for policy in self.Policy_Hash_DVG[1].values():
                try:
                    policy.delete()
                except Exception:
                    pass
        self.DVG_Hash.clear()
        self.Endpoint_Hash_MAC.clear()
        self.Endpoint_Hash_IPv4.clear()
        self.Endpoint_Hash_IPv6.clear()
        #Delete all tunnels
        self.Tunnel_Endpoints_Hash_IPv4.clear()
        self.Tunnel_Endpoints_Hash_IPv6.clear()
        #Delete all dps clients
        self.DPSClients_Hash_IPv4.clear()
        self.DPSClients_Hash_IPv6.clear()
        self.Policy_Hash_DVG[0].clear()
        self.Policy_Hash_DVG[1].clear()
        #Destroy IP subnet list
        self.IP_Subnet_List.destroy()
        #Destroy Address Resolution
        self.AddressResolution.delete()
        #Destroy Conflict Detection
        self.ConflictDetection.delete()
        #Destroy Multicast
        self.Multicast.delete()
        return

    def ip_subnet_add(self, ip_value, mask_value, gateway, mode):
        '''
        Adds a IP Subnet to List
        @param ip_value: IP Address of Subnet
        @type ip_value: Integer
        @param mask_value: Mask of Subnet
        @type mask_value: Integer
        @param gateway: Gateway of Subnet
        @type gateway: Integer
        @param mode: Mode of Subnet
        @type mode: Integer (0 = Dedicated, 1 = Shared)
        @return: The status of the operation
        @rtype: dove_status (defined in include/status.h) Integer
        '''
        ret_val = self.IP_Subnet_List.add(ip_value, mask_value, gateway, mode)
        if ret_val == DOVEStatus.DOVE_STATUS_OK:
            #Add to implicit gateway collection
            self.ImplicitGatewayIPListv4.add(socket.AF_INET, gateway)
        return ret_val

    def ip_subnet_delete(self, ip_value, mask_value):
        '''
        Deletes a IP Subnet from List
        @param ip_value: IP Address of Subnet
        @type ip_value: Integer
        @param mask_value: Mask of Subnet
        @type mask_value: Integer
        @return: The status of the operation
        @rtype: dove_status (defined in include/status.h) Integer
        '''
        while True:
            #Get the gateway associated with this subnet
            ret_val, subnet_ip, subnet_mask, subnet_mode, subnet_gateway = self.ip_subnet_get(
                ip_value, mask_value)
            if ret_val != DOVEStatus.DOVE_STATUS_OK:
                break
            #Remove the gateway from the Implicit Gateway collection
            self.ImplicitGatewayIPListv4.remove(socket.AF_INET, subnet_gateway)
            #Remove the Subnet
            ret_val = self.IP_Subnet_List.delete(ip_value, mask_value)
            break
        return ret_val

    def ip_subnet_lookup(self, ip_value):
        '''
        Check if a given IP falls into a subnet in the list and get the subnet
        @param ip_value: IP Address
        @type ip_value: Integer
        @return: status, subnet_ip, subnet_mask, subnet_mode, subnet_gateway
        @rtype: Integer, Integer, Integer, Integer, Integer
        '''
        return self.IP_Subnet_List.lookup(ip_value)

    def ip_subnet_get(self, ip_value, mask_value):
        '''
        Get a exact subnet according to IP and Mask pair
        @param ip_value: IP Address
        @type ip_value: Integer
        @param mask_value: Mask of Subnet
        @type mask_value: Integer
        @return: status, subnet_ip, subnet_mask, subnet_mode, subnet_gateway
        @rtype: Integer, Integer, Integer, Integer, Integer
        '''
        return self.IP_Subnet_List.get(ip_value, mask_value)

    def ip_subnet_show(self):
        '''
        List all IP Subnets from List
        @return: The status of the operation
        @rtype: dove_status (defined in include/status.h) Integer
        '''
        return self.IP_Subnet_List.show()

    def ip_subnet_flush(self):
        '''
        Flush all IP Subnets from List
        @return: The status of the operation
        @rtype: dove_status (defined in include/status.h) Integer
        '''
        return self.IP_Subnet_List.flush()

    def process_lookup_not_found(self, dps_client_IP_type, dps_client_IP_val,
                                 source_dvg, vIP_type, vIP_value, vIP_packed):
        '''
        This routine handles the case of vIP lookup failure in the list of Endpoints
        in a domain. The client protocol handler sends out the External Gateway
        as the answer, but in the background this routine checks with all relevant
        DPS Client in every VNID in this domain to resolve the Address
        @param dps_client_IP_type: socket.AF_INET6 or socket.AF_INET
        @type dps_client_IP_type: Integer
        @param dps_client_IP_val: socket.AF_INET6 or socket.AF_INET
        @type dps_client_IP_val: Integer
        @param source_dvg: The Source VNID
        @type source_dvg: DVG
        @param vIP_type: socket.AF_INET or socket.AF_INET6
        @type vIP_type: Integer
        @param vIP_val: IPv6 or IPv4 Address
        @type vIP_val: String or Integer
        @param vIP_packed: vIP packed
        @type vIP_packed: ByteArray
        '''
        if not self.valid:
            return
        if ((self.AddressResolution.total >= self.AddressResolution.total_max)
                or (len(self.AddressResolution.endpoint_resolution) >=
                    self.AddressResolution.vIP_not_found_max)):
            return
        while True:
            try:
                if dps_client_IP_type == socket.AF_INET:
                    dps_client = self.DPSClients_Hash_IPv4[dps_client_IP_val]
                else:
                    dps_client = self.DPSClients_Hash_IPv6[dps_client_IP_val]
            except Exception:
                break
            #Store in Address Resolution Structure
            fSendAddressResolution = self.AddressResolution.process_lookup_not_found(
                dps_client, source_dvg, vIP_type, vIP_value)
            #Queue Work Item to Send Address Resolution Queries
            if fSendAddressResolution:
                DpsCollection.address_resolution_queue.put(
                    (self.send_resolution_work, (vIP_value, vIP_packed)))
            break
        return

    def send_resolution_work(self, vIP_tuple):
        '''
        This routine sends address resolution queries to all dps clients in all DVGs
        @attention: Do not call this routine with global lock held
        @param vIP_tuple: (vIP_value, vIP_packed)
        @type vIP_tuple: Tuple of (String or Integer, ByteArray)
        '''
        #log.warning('send_resolution_work: Enter\r')
        vIP_value = vIP_tuple[0]
        vIP_packed = vIP_tuple[1]
        DpsCollection.global_lock.acquire()
        while True:
            if not self.valid:
                break
            try:
                dvg_list = self.DVG_Hash.values()
            except Exception:
                dvg_list = []
            #Send Address Resolution to all DVGS
            #Drop Lock in between DVGs to allow other threads to run
            DpsCollection.global_lock.release()
            for dvg in dvg_list:
                DpsCollection.global_lock.acquire()
                try:
                    ret_val, subnet_ip, subnet_mask, subnet_mode, subnet_gateway = dvg.ip_subnet_lookup(
                        vIP_value)
                    if ret_val == DOVEStatus.DOVE_STATUS_OK:
                        dvg.send_address_resolution(vIP_packed)
                except Exception:
                    pass
                DpsCollection.global_lock.release()
            DpsCollection.global_lock.acquire()
            #Store self in Global Timer
            DpsCollection.Address_Resolution_Requests[self.unique_id] = self
            break
        DpsCollection.global_lock.release()
        #log.warning('send_resolution_work: Exit\r')
        return

    def mass_transfer_finish(self, dps_location, fcomplete, weight):
        '''
        This routine will be called by the Mass Transfer Callback when mass transfer
        of data to remote node is done.
        @param dps_location: The location of the remote node
        @type dps_location: IPAddressLocation
        @param fcomplete: Indicates if the transfer was complete or had to be cancelled
                          due to some issue
        @type fcomplete: False
        @param weight: The weight of the mass transfer
        @type weight: Integer
        '''
        message = 'Domain %d: Mass Transfer finished to %s, completed %s' % (
            self.unique_id, dps_location.show_ip(), fcomplete)
        dcslib.dps_cluster_write_log(DpsLogLevels.INFO, message)
        mass_transfer_complete = False
        DpsCollection.global_lock.acquire()
        while True:
            try:
                if self.mass_transfer is None:
                    break
                #Don't make self.mass_transfer None till activate has been exchanged
                #self.mass_transfer = None
                DpsCollection.mass_transfer_lock.acquire()
                try:
                    DpsCollection.MassTransfer_Active -= weight
                    if DpsCollection.MassTransfer_Active < 0:
                        message = 'Domain %s: Mass Transfer finished, accounting problem with mass transfer count %s'
                        dcslib.dps_cluster_write_log(DpsLogLevels.CRITICAL,
                                                     message)
                except Exception:
                    pass
                DpsCollection.mass_transfer_lock.release()
                if fcomplete and self.valid:
                    self.mass_transfer_forward_nodes[
                        dps_location.ip_value] = dps_location
                    mass_transfer_complete = True
            except Exception:
                pass
            break
        DpsCollection.global_lock.release()
        if mass_transfer_complete:
            message = 'Domain %s: Mass Transfer Complete, sending Activate message to remote Node %s' % (
                self.unique_id, dps_location.show_ip())
            dcslib.dps_cluster_write_log(DpsLogLevels.NOTICE, message)
            ret = dcslib.dps_domain_activate_on_node(
                dps_location.ip_value_packed, self.unique_id,
                self.replication_factor)
            if ret != 0:
                message = 'Domain %s: Activate on Node %s failed, clearing local forwarding cache' % (
                    self.unique_id, dps_location.show_ip())
                dcslib.dps_cluster_write_log(DpsLogLevels.NOTICE, message)
                try:
                    del self.mass_transfer_forward_nodes[dps_location.ip_value]
                except Exception:
                    pass
        else:
            message = 'Domain %s: Mass Transfer canceled, sending Deactivate message to remote Node %s' % (
                self.unique_id, dps_location.show_ip())
            dcslib.dps_cluster_write_log(DpsLogLevels.NOTICE, message)
            ret = dcslib.dps_domain_deactivate_on_node(
                dps_location.ip_value_packed, self.unique_id)
            if ret != 0:
                message = 'Domain %s: Deactivate on Node %s Failed' % (
                    self.unique_id, dps_location.show_ip())
                dcslib.dps_cluster_write_log(DpsLogLevels.NOTICE, message)
        DpsCollection.global_lock.acquire()
        self.mass_transfer = None
        DpsCollection.global_lock.release()
        return

    def mass_transfer_processing(self):
        '''
        This routine determines if the local node is in the midst of mass
        transfer processing
        @return - True if mass transfer is underway
        @rtype - Boolean
        '''
        if self.mass_transfer is not None or len(
                self.mass_transfer_forward_nodes) > 0:
            return True
        else:
            return False

    def send_vm_migration_update_to(self, dps_client, endpoint, vnid,
                                    query_id):
        if not self.active:
            return
        if query_id == 0:
            query_id_use = DpsCollection.generate_query_id()
        else:
            query_id_use = query_id
        # to send to dcslib.send_all_vm_migration_update ()
        vipv4_list = []
        vipv6_list = []
        pipv4_list = endpoint.tunnel_endpoint.ip_listv4.ip_list[:]
        pipv6_list = endpoint.tunnel_endpoint.ip_listv6.ip_list[:]
        for vIP_obj in endpoint.vIP_set.values():
            if vIP_obj.fValid:
                if vIP_obj.inet_type == socket.AF_INET:
                    vipv4_list.append(vIP_obj.ip_value)
                elif vIP_obj.inet_type == socket.AF_INET6:
                    vipv6_list.append(vIP_obj.ip_value)
        ret_val = dcslib.send_all_vm_migration_update(
            dps_client.location.ip_value_packed,  #DPS Client Location IP
            dps_client.location.port,  #DPS Client Port
            vnid,  #VNID ID
            query_id_use,
            endpoint.dvg.unique_id,
            endpoint.version,
            pipv4_list,
            pipv6_list,
            endpoint.vMac,
            vipv4_list,
            vipv6_list)
        if ret_val != 0:
            message = 'send_all_vm_migration_update FAILED with value %d' % (
                ret_val)
            dcslib.dps_data_write_log(DpsLogLevels.NOTICE, message)
        return

    def send_vm_migration_update(self, endpoint, vnid):
        '''
        This routine is used to send a vm migration update to all the DPS clients
        handling the domain.
        '''
        if not self.active:
            return
        DpsCollection.global_lock.acquire()
        #Create a set of dps_clients
        dps_clients = {}
        for dps_client in self.DPSClients_Hash_IPv4.values():
            dps_clients[dps_client] = True
        for dps_client in self.DPSClients_Hash_IPv6.values():
            dps_clients[dps_client] = True
        for dps_client in dps_clients.keys():
            self.send_vm_migration_update_to(dps_client, endpoint, vnid, 0)
        dps_clients.clear()
        DpsCollection.global_lock.release()
        return

    def show(self, fdetails):
        '''
        Display Contents of a Domain
        @param fdetails: Whether to show detailed information
        @type fdetails: Integer (0 = False, 1 = True)
        '''
        print '------------------------------------------------------------------\r'
        print 'Showing Domain: %s\r' % (self.unique_id)
        #############################################################
        #Show list of DVGs.
        #############################################################
        dvg_list = ''
        for dvg in self.DVG_Hash.values():
            dvg_list += str(dvg.unique_id) + ', '
        dvg_list = dvg_list.rstrip()
        dvg_list = dvg_list.rstrip(',')
        print 'VNIDs: [%s]\r' % (dvg_list)
        ##############################################################
        ##Show number of DPS Clients
        ##############################################################
        dps_client_count = len(self.DPSClients_Hash_IPv4) + len(
            self.DPSClients_Hash_IPv6)
        if fdetails and dps_client_count > 0:
            print '------------------------- DPS Clients ----------------------------\r'
            for dps_clients in self.DPSClients_Hash_IPv4.values():
                dps_clients.show()
            for dps_clients in self.DPSClients_Hash_IPv6.values():
                dps_clients.show()
            print '------------------------------------------------------------------\r'
        else:
            print 'DPS Clients: Total %s\r' % dps_client_count
        # #############################################################
        # #Show number of tunnels.
        # #############################################################
        # tunnel_count = len(self.Tunnel_Endpoints_Hash_IPv4)+ len(self.Tunnel_Endpoints_Hash_IPv6)
        # if fdetails and tunnel_count > 0:
        #     tunnel_set = {}
        #     for tunnel in self.Tunnel_Endpoints_Hash_IPv4.values():
        #         tunnel_set[tunnel] = True
        #     for tunnel in self.Tunnel_Endpoints_Hash_IPv6.values():
        #         tunnel_set[tunnel] = True
        #     print '---------------------- Tunnel Endpoints --------------------------\r'
        #     for tunnel in tunnel_set.keys():
        #         tunnel.show_details()
        #     tunnel_set.clear()
        #     print '------------------------------------------------------------------\r'
        # else:
        #     print 'Tunnels: Total %s\r'%tunnel_count
        #############################################################
        #Show number of endpoints.
        #############################################################
        endpoint_count = len(self.Endpoint_Hash_MAC)
        if fdetails and endpoint_count > 0:
            print '-------------------------- Endpoints -----------------------------\r'
            for endpoint in self.Endpoint_Hash_MAC.values():
                endpoint.show()
        else:
            print 'Endpoints: Total %s\r' % endpoint_count
            endpoint_ip = len(self.Endpoint_Hash_IPv4) + len(
                self.Endpoint_Hash_IPv6)
            print 'Endpoints: Total Number of vIP Addresses %s\r' % endpoint_ip
        #############################################################
        #Show Implicit Gateways.
        #############################################################
        count = len(self.ImplicitGatewayIPListv4.ip_hash) + len(
            self.ImplicitGatewayIPListv6.ip_hash)
        if fdetails and count > 0:
            print '------------------------- Implicit Gateways ----------------------\r'
            if len(self.ImplicitGatewayIPListv4.ip_hash) > 0:
                self.ImplicitGatewayIPListv4.show()
            if len(self.ImplicitGatewayIPListv6.ip_hash) > 0:
                self.ImplicitGatewayIPListv6.show()
        else:
            print 'Implicit Gateways: Total %s\r' % count
        ##############################################################
        ##Show Dedicated Subnet Lists
        ##############################################################
        if self.IP_Subnet_List.count > 0:
            print 'Subnet List: Total %s\r' % self.IP_Subnet_List.count
            self.ip_subnet_show()
        #############################################################
        #Show Policies.
        #############################################################
        count = len(self.Policy_Hash_DVG[0])
        if fdetails and count > 0:
            print '----------------------- Unicast Policies -------------------------\r'
            for policy in self.Policy_Hash_DVG[0].values():
                if policy.src_dvg == policy.dst_dvg and policy.action_connectivity == policy.action_forward:
                    continue
                print '%s\r' % policy.show()
        else:
            print 'Policy Count %s\r' % count
        #############################################################
        #Show Nodes to whom requests are being forwarded and
        #Mass Transfer
        #############################################################
        if self.mass_transfer is not None:
            print '\r'
            print 'Ongoing mass transfer to %s\r' % self.mass_transfer.remote_location.show(
            )
        if len(self.mass_transfer_forward_nodes) > 0:
            for remote_location in self.mass_transfer_forward_nodes.values():
                print 'Forwarding Requests to DPS Node %s\r' % remote_location.show(
                )
        return

    def show_mass_transfer(self):
        '''
        '''
        if self.mass_transfer is not None:
            print '\r'
            print 'Ongoing mass transfer to %s, Stage %s\n' % (
                self.mass_transfer.remote_location.show_ip(),
                self.mass_transfer.stage_get())
            self.mass_transfer.show()
        if len(self.mass_transfer_forward_nodes) > 0:
            for remote_location in self.mass_transfer_forward_nodes.values():
                print 'Forwarding Requests to DPS Node %s\r' % remote_location.show(
                )
        return