Пример #1
0
 def __init__(self, domain, ip_type, ip_val, port):
     '''
     Constructor:
     This routine assumes that the IP address of the DPS Client 
     uniquely identifies the DPS Client.
     @param domain: The Domain object
     @type domain: Domain
     @param ip_type: socket.AF_INET6 or socket.AF_INET
     @type ip_type: Integer
     @param ip_val: The Value of the IP Address
     @type ip_val: String (IPv6) or Integer
     @param port: The DPS Client Port (for UDP communication)
     @type port: Integer
     '''
     self.domain = domain
     #DPS Client Location i.e. the UDP Port and Location
     self.location = IPAddressLocation(ip_type, ip_val, port)
     #List of Tunnel Endpoints
     #This is to store the Tunnel Endpoint IP Address
     self.Tunnel_Endpoints_Hash_IPv4 = {}
     self.Tunnel_Endpoints_Hash_IPv6 = {}
     ##Failure count
     self.failure_count = self.failure_count_max
     self.version = 0
     self.valid = True
     #Add to Domain collection
     Domain.dps_client_add(self.domain, self)
Пример #2
0
 def __init__(self, domain, ip_type, ip_val, port, client_type):
     '''
     Constructor:
     This routine assumes that the IP address of the DPS Client 
     uniquely identifies the DPS Client.
     @param domain: The Domain object for which this DPSHostClient was first 
                    created
     @type domain: Domain
     @param ip_type: socket.AF_INET6 or socket.AF_INET
     @type ip_type: Integer
     @param ip_val: The Value of the IP Address
     @type ip_val: String (IPv6) or Integer
     @param port: The DPS Client Port (for UDP communication)
     @type port: Integer
     @param client_type: What kind of Client is it
     @type client_type: Should be one of DpsClientType
     '''
     self.frequency = self.heartbeat_frequency[client_type]
     self.domains = {}
     self.domains[domain.unique_id] = domain
     #DPS Client Location i.e. the UDP Port and Location
     self.location = IPAddressLocation(ip_type, ip_val, port)
     self.client_type = client_type
     self.client_types = {}
     self.client_types[client_type] = True
     self.last_contact = time.time()
     #print '%s added client_type %s\r'%(self.location.show_ip(), DpsClientType.types[client_type])
     #Add self to global collection
     try:
         DPSClientHost.Collection[ip_val] = self
     except Exception:
         pass
     self.valid = True
Пример #3
0
 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)
Пример #4
0
 def __init__(self, domain, ip_type, ip_val, port):
     '''
     Constructor:
     This routine assumes that the IP address of the DPS Client 
     uniquely identifies the DPS Client.
     @param domain: The Domain object
     @type domain: Domain
     @param ip_type: socket.AF_INET6 or socket.AF_INET
     @type ip_type: Integer
     @param ip_val: The Value of the IP Address
     @type ip_val: String (IPv6) or Integer
     @param port: The DPS Client Port (for UDP communication)
     @type port: Integer
     '''
     self.domain = domain
     #DPS Client Location i.e. the UDP Port and Location
     self.location = IPAddressLocation(ip_type, ip_val, port)
     #List of Tunnel Endpoints
     #This is to store the Tunnel Endpoint IP Address
     self.Tunnel_Endpoints_Hash_IPv4 = {}
     self.Tunnel_Endpoints_Hash_IPv6 = {}
     ##Failure count
     self.failure_count = self.failure_count_max
     self.version = 0
     self.valid = True
     #Add to Domain collection
     Domain.dps_client_add(self.domain, self)
Пример #5
0
 def __init__(self, domain, ip_type, ip_val, port, client_type):
     '''
     Constructor:
     This routine assumes that the IP address of the DPS Client 
     uniquely identifies the DPS Client.
     @param domain: The Domain object for which this DPSHostClient was first 
                    created
     @type domain: Domain
     @param ip_type: socket.AF_INET6 or socket.AF_INET
     @type ip_type: Integer
     @param ip_val: The Value of the IP Address
     @type ip_val: String (IPv6) or Integer
     @param port: The DPS Client Port (for UDP communication)
     @type port: Integer
     @param client_type: What kind of Client is it
     @type client_type: Should be one of DpsClientType
     '''
     self.frequency = self.heartbeat_frequency[client_type]
     self.domains = {}
     self.domains[domain.unique_id] = domain
     #DPS Client Location i.e. the UDP Port and Location
     self.location = IPAddressLocation(ip_type, ip_val, port)
     self.client_type = client_type
     self.client_types = {}
     self.client_types[client_type] = True
     self.last_contact = time.time()
     #print '%s added client_type %s\r'%(self.location.show_ip(), DpsClientType.types[client_type])
     #Add self to global collection
     try:
         DPSClientHost.Collection[ip_val] = self
     except Exception:
         pass
     self.valid = True
Пример #6
0
 def __init__(self, vIP_type, vIP_value):
     '''
     Constructor:
     @param vIP_type: socket.AF_INET or socket.AF_INET6
     @type vIP_type: Integer
     @param vIP_value: The Virtual IP Address
     @type vIP_value: String (IPv6), Integer (IPv4)
     '''
     self.vIP = IPAddressLocation(vIP_type, vIP_value, 0)
     #List of Waiters which are waiting for answer on this Resolution
     #Key (DPS Client)
     self.dps_clients = {}
     #Total number of waiters
     self.total = 0
     #Retry is decremented in every cycle
     self.retry = 2
Пример #7
0
 def __init__(self, domain_id, vIP_type, vIP_value):
     '''
     Constructor:
     @param domain_id: The Domain ID
     @type domain_id: Integer
     @param vIP_type: socket.AF_INET or socket.AF_INET6
     @type vIP_type: Integer
     @param vIP_value: The Virtual IP Address
     @type vIP_value: String (IPv6), Integer (IPv4)
     '''
     self.domain_id = domain_id
     self.vIP = IPAddressLocation(vIP_type, vIP_value, 0)
     #Set of Endpoints that claim to have this vIP
     self.endpoints_claim = {}
     #Set of Endpoint which actually have this vIP
     self.endpoints_registered = {}
     #Retry is decremented in every cycle
     self.retry = 2
     #Who owns the endpoint at this time
     self.endpoint_owner = None
Пример #8
0
class DPSClient:
    '''
    This represents the DPS Client which is communicating via the DPS
    Client Server Protocol. Each DPS Client is associated with one
    or more Tunnel Endpoints.
    NOTE: Each DPSClient will have multiple instances every every Domain
          it hosts TunnelEndpoint on. In other words if a DPSClient hosts
          TunnelEndpoint on Domain A and Domain B, then there will be 2
          independent instances of that DPSClient, 1 in Domain A and 1
          in Domain B.
    '''

    #A maximum of "max_failure" failures is tolerated from a DPS Client. After
    #that the DPS Client will have been deemed to be down and will be removed
    #from the collection
    failure_count_max = 4

    def __init__(self, domain, ip_type, ip_val, port):
        '''
        Constructor:
        This routine assumes that the IP address of the DPS Client 
        uniquely identifies the DPS Client.
        @param domain: The Domain object
        @type domain: Domain
        @param ip_type: socket.AF_INET6 or socket.AF_INET
        @type ip_type: Integer
        @param ip_val: The Value of the IP Address
        @type ip_val: String (IPv6) or Integer
        @param port: The DPS Client Port (for UDP communication)
        @type port: Integer
        '''
        self.domain = domain
        #DPS Client Location i.e. the UDP Port and Location
        self.location = IPAddressLocation(ip_type, ip_val, port)
        #List of Tunnel Endpoints
        #This is to store the Tunnel Endpoint IP Address
        self.Tunnel_Endpoints_Hash_IPv4 = {}
        self.Tunnel_Endpoints_Hash_IPv6 = {}
        ##Failure count
        self.failure_count = self.failure_count_max
        self.version = 0
        self.valid = True
        #Add to Domain collection
        Domain.dps_client_add(self.domain, self)
        #self.show(None)

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

    def tunnel_endpoint_delete(self, tunnel_endpoint):
        '''
        Removes a Tunnel Endpoint from the collection
        @param tunnel_endpoint: The Tunnel Endpoint
        @type tunnel_endpoint: TunnelEndpoint Object
        '''
        #log.info('DPSClient.tunnel_endpoint_delete %s', tunnel_endpoint.primary_ip().show())
        ip_list = tunnel_endpoint.ip_listv4.ip_list
        for ip_value in ip_list:
            try:
                del self.Tunnel_Endpoints_Hash_IPv4[ip_value]
            except Exception:
                pass
        ip_list = tunnel_endpoint.ip_listv6.ip_list
        for ip_value in ip_list:
            try:
                del self.Tunnel_Endpoints_Hash_IPv6[ip_value]
            except Exception:
                pass
        if ((len(self.Tunnel_Endpoints_Hash_IPv4) == 0) and 
            (len(self.Tunnel_Endpoints_Hash_IPv6) == 0)):
            #log.info('DPSClient.tunnel_endpoint_delete: No tunnel endpoints')
            #No other tunnels attached
            Domain.dps_client_delete(self.domain, self)
        #self.show(None)

    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 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
        '''
        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
        if ((len(self.Tunnel_Endpoints_Hash_IPv4) == 0) and 
            (len(self.Tunnel_Endpoints_Hash_IPv6) == 0)):
            #log.info('DPSClient.tunnel_endpoint_delete: No tunnel endpoints')
            #No other tunnels attached
            Domain.dps_client_delete(self.domain, self)
        return

    def delete(self):
        '''
        Destructor:
        '''
        if not self.valid:
            return
        self.valid = False
        #Remove from GlobalCollection
        DPSClientHost.Host_Delete_All(self.domain, self.location.ip_value)
        #Remove self from VNID_Broadcast_Updates_To
        for key in DpsCollection.VNID_Broadcast_Updates_To.keys():
            try:
                tuple_value = DpsCollection.VNID_Broadcast_Updates_To[key]
                dps_client = tuple_value[1]
                if dps_client == self:
                    del DpsCollection.VNID_Broadcast_Updates_To[key]
            except Exception:
                pass
        #Remove self from DPS Client Updates
        for key in DpsCollection.Policy_Updates_To.keys():
            try:
                tuple_value = DpsCollection.Policy_Updates_To[key]
                dps_client = tuple_value[1]
                if dps_client == self:
                    del DpsCollection.Policy_Updates_To[key]
            except Exception:
                pass
        #Remove from Gateway_Updates_To
        for key in DpsCollection.Gateway_Updates_To.keys():
            try:
                tuple_value = DpsCollection.Gateway_Updates_To[key]
                dps_client = tuple_value[1]
                if dps_client == self:
                    del DpsCollection.Gateway_Updates_To[key]
            except Exception:
                pass
        #Remove from VNID_Multicast_Updates_To
        for key in DpsCollection.VNID_Multicast_Updates_To.keys():
            try:
                tuple_value = DpsCollection.VNID_Multicast_Updates_To[key]
                dps_client = tuple_value[1]
                if dps_client == self:
                    del DpsCollection.VNID_Multicast_Updates_To[key]
            except Exception:
                pass
        #Remove from Address_Resolution_Requests_To
        for key in DpsCollection.Address_Resolution_Requests_To.keys():
            try:
                tuple_value = DpsCollection.Address_Resolution_Requests_To[key]
                dps_client = tuple_value[1]
                if dps_client == self:
                    del DpsCollection.Address_Resolution_Requests_To[key]
            except Exception:
                continue
        for tunnel in self.Tunnel_Endpoints_Hash_IPv4.values():
            tunnel.delete()
        for tunnel in self.Tunnel_Endpoints_Hash_IPv6.values():
            tunnel.delete()
        Domain.dps_client_delete(self.domain, self)

    def show(self):
        '''
        Display Details
        '''
        print 'DPS Client: %s\r'%(self.location.show())
        print '---------------------- Tunnel Endpoints --------------------------\r'
        #############################################################
        #Show list of tunnels.
        #############################################################
        #First create a unique tunnel list
        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
        for tunnel in tunnel_set.keys():
            tunnel.show()
        tunnel_set.clear()
        print '------------------------------------------------------------------\r'
        return
Пример #9
0
class DPSClientHost:
    '''
    This represents the DPS Client which is communicating via the DPS
    Client Server Protocol.
    @attention: A DCSHostClient is not associated with any specific domain
                (unlike the DPSClient object). This object is maintained to 
                keep in contact with that Host via heartbeat messages
    '''
    Collection = {}

    #The frequency (seconds) at which to send heartbeat to DPS Clients
    heartbeat_frequency = {
        DpsClientType.dove_switch: 60,
        DpsClientType.external_gateway: 3,
        DpsClientType.vlan_gateway: 20
    }

    #A maximum of no contact time before DPS Client is marked as down
    heartbeat_no_contact = {
        DpsClientType.dove_switch: 3600,
        DpsClientType.external_gateway: 20,
        DpsClientType.vlan_gateway: 600
    }

    def __init__(self, domain, ip_type, ip_val, port, client_type):
        '''
        Constructor:
        This routine assumes that the IP address of the DPS Client 
        uniquely identifies the DPS Client.
        @param domain: The Domain object for which this DPSHostClient was first 
                       created
        @type domain: Domain
        @param ip_type: socket.AF_INET6 or socket.AF_INET
        @type ip_type: Integer
        @param ip_val: The Value of the IP Address
        @type ip_val: String (IPv6) or Integer
        @param port: The DPS Client Port (for UDP communication)
        @type port: Integer
        @param client_type: What kind of Client is it
        @type client_type: Should be one of DpsClientType
        '''
        self.frequency = self.heartbeat_frequency[client_type]
        self.domains = {}
        self.domains[domain.unique_id] = domain
        #DPS Client Location i.e. the UDP Port and Location
        self.location = IPAddressLocation(ip_type, ip_val, port)
        self.client_type = client_type
        self.client_types = {}
        self.client_types[client_type] = True
        self.last_contact = time.time()
        #print '%s added client_type %s\r'%(self.location.show_ip(), DpsClientType.types[client_type])
        #Add self to global collection
        try:
            DPSClientHost.Collection[ip_val] = self
        except Exception:
            pass
        self.valid = True

    def update_add(self, domain, port, client_type):
        '''
        This routine updates the dps client with the parameters
        @param domain: The Domain object for which this DPSHostClient was first 
                       created
        @type domain: Domain
        @param port: The DPS Client Port (for UDP communication)
        @type port: Integer
        @param client_type: What kind of Client is it
        @type client_type: Should be one of DpsClientType
        '''
        if not self.valid:
            return
        self.domains[domain.unique_id] = domain
        self.location.port = port
        self.client_types[client_type] = True
        #Get the client type with the highest (lowest in time difference) frequency heartbeat requirement
        try:
            if DPSClientHost.heartbeat_frequency[
                    client_type] < DPSClientHost.heartbeat_frequency[
                        self.client_type]:
                self.client_type = client_type
                print '%s changing client_type to %s\r' % (
                    self.location.show_ip(), DpsClientType.types[client_type])
        except Exception:
            self.client_type = client_type
        return

    def update_delete(self, domain, client_type):
        '''
        This routine updates the dps client with the parameters
        @param domain: The Domain object for which this DPSHostClient was first 
                       created
        @type domain: Domain
        @param port: The DPS Client Port (for UDP communication)
        @type port: Integer
        @param client_type: What kind of Client is it
        @type client_type: Should be one of DpsClientType
        '''
        if not self.valid:
            return
        try:
            del self.domains[domain.unique_id]
        except Exception:
            pass
        try:
            del self.client_types[client_type]
        except Exception:
            pass
        if len(self.domains) == 0 or len(self.client_types) == 0:
            self.delete()
            return
        #Get the client type with the highest (lowest in time difference) frequency heartbeat requirement
        try:
            client_types = self.client_types.keys()
            self.client_type = client_types[0]
            client_types = client_types[1:]
            for client_type in client_types:
                if DPSClientHost.heartbeat_frequency[
                        client_type] < DPSClientHost.heartbeat_frequency[
                            self.client_type]:
                    self.client_type = client_type
        except Exception:
            pass
        return

    def touch(self):
        '''
        This routine touches the DPS Client
        '''
        self.last_contact = time.time()
        return

    def domain_add(self, domain):
        '''
        This routine add a domain to the DPSClientHost
        @param domain: The Domain object
        @type domain: Domain
        '''
        self.domains[domain.unique_id] = domain
        return

    def domain_delete(self, domain):
        '''
        This routine deletes the domain from the DPSClientHost
        @param domain: The Domain object
        @type domain: Domain
        '''
        try:
            del self.domains[domain.unique_id]
        except Exception:
            pass
        if len(self.domains) == 0:
            self.delete()
        return

    def vnid_random_get(self):
        '''
        This gets a random vnid to send the heartbeat to.
        @raise exception: If no VNID is found
        '''
        domain = self.domains.values()[0]
        vnid = domain.vnid_random_get()
        return vnid

    def delete(self):
        '''
        This routine deletes the object
        '''
        if not self.valid:
            return
        self.valid = False
        domains = self.domains.values()
        for domain in domains:
            try:
                if self.location.inet_type == socket.AF_INET:
                    dps_client_domain = domain.DPSClients_Hash_IPv4[
                        self.location.ip_value]
                else:
                    dps_client_domain = domain.DPSClients_Hash_IPv6[
                        self.location.ip_value]
                dps_client_domain.delete()
            except Exception:
                continue
        self.domains.clear()
        try:
            del DPSClientHost.Collection[self.location.ip_value]
        except Exception:
            pass
        return

    @staticmethod
    def Host_Add(domain, ip_type, ip_val, port, client_type):
        '''
        This is the routine calling routines should invoke to add a DPS Client
        to the collection
        @attention: This routine must be called with the global lock held
        @param domain: The Domain object
        @type domain: Domain
        @param ip_type: socket.AF_INET6 or socket.AF_INET
        @type ip_type: Integer
        @param ip_val: The Value of the IP Address
        @type ip_val: String (IPv6) or Integer
        @param port: The DPS Client Port (for UDP communication)
        @type port: Integer
        @param client_type: What kind of Client is it
        @type client_type: Should be one of DpsClientType
        '''
        #print 'Host_Add: Enter\r'
        try:
            dps_client = DPSClientHost.Collection[ip_val]
            dps_client.update_add(domain, port, client_type)
        except Exception:
            dps_client = DPSClientHost(domain, ip_type, ip_val, port,
                                       client_type)
        #print 'Host_Add: Exit\r'
        return

    @staticmethod
    def Host_Delete(domain, ip_val, client_type):
        '''
        This is the routine calling routines should invoke to add a DPS Client
        to the collection
        @attention: This routine must be called with the global lock held
        @param domain: The Domain object
        @type domain: Domain
        @param ip_val: The Value of the IP Address
        @type ip_val: String (IPv6) or Integer
        @param client_type: What kind of Client is it
        @type client_type: Should be one of DpsClientType
        '''
        try:
            dps_client = DPSClientHost.Collection[ip_val]
            dps_client.update_delete(domain, client_type)
        except Exception:
            pass
        return

    @staticmethod
    def Host_Delete_All(domain, ip_val):
        '''
        This is the routine calling routines should invoke to add a DPS Client
        to the collection
        @attention: This routine must be called with the global lock held
        @param domain: The Domain object
        @type domain: Domain
        @param ip_val: The Value of the IP Address
        @type ip_val: String (IPv6) or Integer
        '''
        try:
            dps_client = DPSClientHost.Collection[ip_val]
            dps_client.delete()
        except Exception:
            pass
        return

    @staticmethod
    def Host_Touch(ip_val, port):
        '''
        This routine touches the Host
        @param ip_val: The value
        @param port: The port of the DPS Client
        '''
        try:
            dps_client = DPSClientHost.Collection[ip_val]
            if port != 0:
                dps_client.location.port = port
            dps_client.touch()
        except Exception:
            pass
        return

    @staticmethod
    def Domain_Deleted_Locally(domain):
        '''
        This routine should be called when a domain is deleted or de-activated
        from the local DCS Server Node
        @attention: This routine must be called with the global lock held
        @param domain: The Domain object
        @type domain: Domain
        '''
        try:
            dps_clients = DPSClientHost.Collection.values()
            for dps_client in dps_clients:
                try:
                    dps_client.domain_delete(domain)
                except Exception:
                    pass
        except Exception:
            pass
        return

    @staticmethod
    def Send_Heartbeat():
        '''
        This routine sends Heartbeats to all DPS Client which have not been
        contacted for the specified amount of time. 
        '''
        curr_time = time.time()
        try:
            dps_clients = DPSClientHost.Collection.values()
            for dps_client in dps_clients:
                try:
                    time_diff = int(curr_time - dps_client.last_contact)
                    client_type = dps_client.client_type
                    time_no_contact = DPSClientHost.heartbeat_no_contact[
                        client_type]
                    time_heartbeat_send = DPSClientHost.heartbeat_frequency[
                        client_type]
                    if time_diff > time_no_contact:
                        print 'No contact from DPS Client %s for %s seconds. Deleting!!!\r' % (
                            dps_client.location.show_ip(), time_diff)
                        dps_client.delete()
                    elif time_diff >= time_heartbeat_send:
                        vnid = dps_client.vnid_random_get()
                        query_id = DpsCollection.generate_query_id()
                        dcslib.send_heartbeat(
                            dps_client.location.ip_value_packed,
                            dps_client.location.port, vnid, query_id)
                except Exception:
                    continue
        except Exception:
            pass
        return

    @staticmethod
    def show():
        curr_time = time.time()
        print '%s %s\r' % ('DCS Clients'.rjust(20), 'Age Time'.rjust(20))
        try:
            dps_clients = DPSClientHost.Collection.values()
            for dps_client in dps_clients:
                time_diff = int(curr_time - dps_client.last_contact)
                print '%s %s\r' % (dps_client.location.show_ip().rjust(20),
                                   str(time_diff).rjust(20))
        except Exception:
            pass
        return
Пример #10
0
class DPSClient:
    '''
    This represents the DPS Client which is communicating via the DPS
    Client Server Protocol. Each DPS Client is associated with one
    or more Tunnel Endpoints.
    NOTE: Each DPSClient will have multiple instances every every Domain
          it hosts TunnelEndpoint on. In other words if a DPSClient hosts
          TunnelEndpoint on Domain A and Domain B, then there will be 2
          independent instances of that DPSClient, 1 in Domain A and 1
          in Domain B.
    '''

    #A maximum of "max_failure" failures is tolerated from a DPS Client. After
    #that the DPS Client will have been deemed to be down and will be removed
    #from the collection
    failure_count_max = 4

    def __init__(self, domain, ip_type, ip_val, port):
        '''
        Constructor:
        This routine assumes that the IP address of the DPS Client 
        uniquely identifies the DPS Client.
        @param domain: The Domain object
        @type domain: Domain
        @param ip_type: socket.AF_INET6 or socket.AF_INET
        @type ip_type: Integer
        @param ip_val: The Value of the IP Address
        @type ip_val: String (IPv6) or Integer
        @param port: The DPS Client Port (for UDP communication)
        @type port: Integer
        '''
        self.domain = domain
        #DPS Client Location i.e. the UDP Port and Location
        self.location = IPAddressLocation(ip_type, ip_val, port)
        #List of Tunnel Endpoints
        #This is to store the Tunnel Endpoint IP Address
        self.Tunnel_Endpoints_Hash_IPv4 = {}
        self.Tunnel_Endpoints_Hash_IPv6 = {}
        ##Failure count
        self.failure_count = self.failure_count_max
        self.version = 0
        self.valid = True
        #Add to Domain collection
        Domain.dps_client_add(self.domain, self)
        #self.show(None)

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

    def tunnel_endpoint_delete(self, tunnel_endpoint):
        '''
        Removes a Tunnel Endpoint from the collection
        @param tunnel_endpoint: The Tunnel Endpoint
        @type tunnel_endpoint: TunnelEndpoint Object
        '''
        #log.info('DPSClient.tunnel_endpoint_delete %s', tunnel_endpoint.primary_ip().show())
        ip_list = tunnel_endpoint.ip_listv4.ip_list
        for ip_value in ip_list:
            try:
                del self.Tunnel_Endpoints_Hash_IPv4[ip_value]
            except Exception:
                pass
        ip_list = tunnel_endpoint.ip_listv6.ip_list
        for ip_value in ip_list:
            try:
                del self.Tunnel_Endpoints_Hash_IPv6[ip_value]
            except Exception:
                pass
        if ((len(self.Tunnel_Endpoints_Hash_IPv4) == 0)
                and (len(self.Tunnel_Endpoints_Hash_IPv6) == 0)):
            #log.info('DPSClient.tunnel_endpoint_delete: No tunnel endpoints')
            #No other tunnels attached
            Domain.dps_client_delete(self.domain, self)
        #self.show(None)

    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 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
        '''
        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
        if ((len(self.Tunnel_Endpoints_Hash_IPv4) == 0)
                and (len(self.Tunnel_Endpoints_Hash_IPv6) == 0)):
            #log.info('DPSClient.tunnel_endpoint_delete: No tunnel endpoints')
            #No other tunnels attached
            Domain.dps_client_delete(self.domain, self)
        return

    def delete(self):
        '''
        Destructor:
        '''
        if not self.valid:
            return
        self.valid = False
        #Remove from GlobalCollection
        DPSClientHost.Host_Delete_All(self.domain, self.location.ip_value)
        #Remove self from VNID_Broadcast_Updates_To
        for key in DpsCollection.VNID_Broadcast_Updates_To.keys():
            try:
                tuple_value = DpsCollection.VNID_Broadcast_Updates_To[key]
                dps_client = tuple_value[1]
                if dps_client == self:
                    del DpsCollection.VNID_Broadcast_Updates_To[key]
            except Exception:
                pass
        #Remove self from DPS Client Updates
        for key in DpsCollection.Policy_Updates_To.keys():
            try:
                tuple_value = DpsCollection.Policy_Updates_To[key]
                dps_client = tuple_value[1]
                if dps_client == self:
                    del DpsCollection.Policy_Updates_To[key]
            except Exception:
                pass
        #Remove from Gateway_Updates_To
        for key in DpsCollection.Gateway_Updates_To.keys():
            try:
                tuple_value = DpsCollection.Gateway_Updates_To[key]
                dps_client = tuple_value[1]
                if dps_client == self:
                    del DpsCollection.Gateway_Updates_To[key]
            except Exception:
                pass
        #Remove from VNID_Multicast_Updates_To
        for key in DpsCollection.VNID_Multicast_Updates_To.keys():
            try:
                tuple_value = DpsCollection.VNID_Multicast_Updates_To[key]
                dps_client = tuple_value[1]
                if dps_client == self:
                    del DpsCollection.VNID_Multicast_Updates_To[key]
            except Exception:
                pass
        #Remove from Address_Resolution_Requests_To
        for key in DpsCollection.Address_Resolution_Requests_To.keys():
            try:
                tuple_value = DpsCollection.Address_Resolution_Requests_To[key]
                dps_client = tuple_value[1]
                if dps_client == self:
                    del DpsCollection.Address_Resolution_Requests_To[key]
            except Exception:
                continue
        for tunnel in self.Tunnel_Endpoints_Hash_IPv4.values():
            tunnel.delete()
        for tunnel in self.Tunnel_Endpoints_Hash_IPv6.values():
            tunnel.delete()
        Domain.dps_client_delete(self.domain, self)

    def show(self):
        '''
        Display Details
        '''
        print 'DPS Client: %s\r' % (self.location.show())
        print '---------------------- Tunnel Endpoints --------------------------\r'
        #############################################################
        #Show list of tunnels.
        #############################################################
        #First create a unique tunnel list
        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
        for tunnel in tunnel_set.keys():
            tunnel.show()
        tunnel_set.clear()
        print '------------------------------------------------------------------\r'
        return
Пример #11
0
 def show(self):
     '''
     '''
     message = '----------------------------------------------'
     dcslib.dps_data_write_log(DpsLogLevels.NOTICE, message)
     if self.global_scope:
         message = 'GLOBAL SCOPE, VNID %s'%self.dvg.unique_id
     else:
         message = 'MULTICAST MAC %s, VNID %s'%(mac_show(self.mac), self.dvg.unique_id)
     dcslib.dps_data_write_log(DpsLogLevels.NOTICE, message)
     if len(self.receiver_all) > 0:
         message = 'MULTICAST Receivers (NO IP Address)'
         dcslib.dps_data_write_log(DpsLogLevels.NOTICE, message)
         count = 1
         for tunnel in self.receiver_all.keys():
             message = '    [%d] Tunnel %s'%(count, tunnel.primary_ip().show())
             dcslib.dps_data_write_log(DpsLogLevels.NOTICE, message)
             count += 1
     if len(self.receiver_iphash) > 0:
         for iphash_key in self.receiver_iphash.keys():
             try:
                 if type(iphash_key) == type(1):
                     ip_address = IPAddressLocation(socket.AF_INET, iphash_key, 0)
                 else:
                     ip_address = IPAddressLocation(socket.AF_INET6, iphash_key, 0)
             except Exception:
                 continue
             message = 'MULTICAST Receivers IP Address %s'%ip_address.show()
             dcslib.dps_data_write_log(DpsLogLevels.NOTICE, message)
             iphash = self.receiver_iphash[iphash_key]
             count = 1;
             for tunnel in iphash.keys():
                 message = '    [%d] Tunnel %s'%(count, tunnel.primary_ip().show())
                 dcslib.dps_data_write_log(DpsLogLevels.NOTICE, message)
                 count += 1
     if len(self.sender_all) > 0:
         message = 'MULTICAST Senders (NO IP Address)'
         dcslib.dps_data_write_log(DpsLogLevels.NOTICE, message)
         count = 1
         for tunnel in self.sender_all.keys():
             message = '    [%d] Tunnel %s'%(count, tunnel.primary_ip().show())
             dcslib.dps_data_write_log(DpsLogLevels.NOTICE, message)
             count += 1
     if len(self.sender_iphash) > 0:
         for iphash_key in self.sender_iphash.keys():
             try:
                 if type(iphash_key) == type(1):
                     ip_address = IPAddressLocation(socket.AF_INET, iphash_key, 0)
                 else:
                     ip_address = IPAddressLocation(socket.AF_INET6, iphash_key, 0)
             except Exception:
                 continue
             message = 'MULTICAST Senders IP Address %s'%ip_address.show()
             dcslib.dps_data_write_log(DpsLogLevels.NOTICE, message)
             iphash = self.sender_iphash[iphash_key]
             count = 1
             for tunnel in iphash.keys():
                 message = '    [%d] Tunnel %s'%(count, tunnel.primary_ip().show())
                 dcslib.dps_data_write_log(DpsLogLevels.NOTICE, message)
                 count += 1
     message = '----------------------------------------------'
     dcslib.dps_data_write_log(DpsLogLevels.NOTICE, message)
     return
Пример #12
0
class DPSClientHost:
    '''
    This represents the DPS Client which is communicating via the DPS
    Client Server Protocol.
    @attention: A DCSHostClient is not associated with any specific domain
                (unlike the DPSClient object). This object is maintained to 
                keep in contact with that Host via heartbeat messages
    '''
    Collection = {}

    #The frequency (seconds) at which to send heartbeat to DPS Clients
    heartbeat_frequency = {DpsClientType.dove_switch: 60,
                           DpsClientType.external_gateway: 3,
                           DpsClientType.vlan_gateway: 20
                           }

    #A maximum of no contact time before DPS Client is marked as down
    heartbeat_no_contact = {DpsClientType.dove_switch: 3600,
                            DpsClientType.external_gateway: 20,
                            DpsClientType.vlan_gateway: 600}

    def __init__(self, domain, ip_type, ip_val, port, client_type):
        '''
        Constructor:
        This routine assumes that the IP address of the DPS Client 
        uniquely identifies the DPS Client.
        @param domain: The Domain object for which this DPSHostClient was first 
                       created
        @type domain: Domain
        @param ip_type: socket.AF_INET6 or socket.AF_INET
        @type ip_type: Integer
        @param ip_val: The Value of the IP Address
        @type ip_val: String (IPv6) or Integer
        @param port: The DPS Client Port (for UDP communication)
        @type port: Integer
        @param client_type: What kind of Client is it
        @type client_type: Should be one of DpsClientType
        '''
        self.frequency = self.heartbeat_frequency[client_type]
        self.domains = {}
        self.domains[domain.unique_id] = domain
        #DPS Client Location i.e. the UDP Port and Location
        self.location = IPAddressLocation(ip_type, ip_val, port)
        self.client_type = client_type
        self.client_types = {}
        self.client_types[client_type] = True
        self.last_contact = time.time()
        #print '%s added client_type %s\r'%(self.location.show_ip(), DpsClientType.types[client_type])
        #Add self to global collection
        try:
            DPSClientHost.Collection[ip_val] = self
        except Exception:
            pass
        self.valid = True

    def update_add(self, domain, port, client_type):
        '''
        This routine updates the dps client with the parameters
        @param domain: The Domain object for which this DPSHostClient was first 
                       created
        @type domain: Domain
        @param port: The DPS Client Port (for UDP communication)
        @type port: Integer
        @param client_type: What kind of Client is it
        @type client_type: Should be one of DpsClientType
        '''
        if not self.valid:
            return
        self.domains[domain.unique_id] = domain
        self.location.port = port
        self.client_types[client_type] = True
        #Get the client type with the highest (lowest in time difference) frequency heartbeat requirement
        try:
            if DPSClientHost.heartbeat_frequency[client_type] < DPSClientHost.heartbeat_frequency[self.client_type]:
                self.client_type = client_type
                print '%s changing client_type to %s\r'%(self.location.show_ip(), DpsClientType.types[client_type])
        except Exception:
            self.client_type = client_type
        return

    def update_delete(self, domain, client_type):
        '''
        This routine updates the dps client with the parameters
        @param domain: The Domain object for which this DPSHostClient was first 
                       created
        @type domain: Domain
        @param port: The DPS Client Port (for UDP communication)
        @type port: Integer
        @param client_type: What kind of Client is it
        @type client_type: Should be one of DpsClientType
        '''
        if not self.valid:
            return
        try:
            del self.domains[domain.unique_id]
        except Exception:
            pass
        try:
            del self.client_types[client_type]
        except Exception:
            pass
        if len(self.domains) == 0 or len(self.client_types) == 0:
            self.delete()
            return
        #Get the client type with the highest (lowest in time difference) frequency heartbeat requirement
        try:
            client_types = self.client_types.keys()
            self.client_type = client_types[0]
            client_types = client_types[1:]
            for client_type in client_types:
                if DPSClientHost.heartbeat_frequency[client_type] < DPSClientHost.heartbeat_frequency[self.client_type]:
                    self.client_type = client_type
        except Exception:
            pass
        return

    def touch(self):
        '''
        This routine touches the DPS Client
        '''
        self.last_contact = time.time()
        return

    def domain_add(self, domain):
        '''
        This routine add a domain to the DPSClientHost
        @param domain: The Domain object
        @type domain: Domain
        '''
        self.domains[domain.unique_id] = domain
        return

    def domain_delete(self, domain):
        '''
        This routine deletes the domain from the DPSClientHost
        @param domain: The Domain object
        @type domain: Domain
        '''
        try:
            del self.domains[domain.unique_id]
        except Exception:
            pass
        if len(self.domains) == 0:
            self.delete()
        return

    def vnid_random_get(self):
        '''
        This gets a random vnid to send the heartbeat to.
        @raise exception: If no VNID is found
        '''
        domain = self.domains.values()[0]
        vnid = domain.vnid_random_get()
        return vnid

    def delete(self):
        '''
        This routine deletes the object
        '''
        if not self.valid:
            return
        self.valid = False
        domains = self.domains.values()
        for domain in domains:
            try:
                if self.location.inet_type == socket.AF_INET:
                    dps_client_domain = domain.DPSClients_Hash_IPv4[self.location.ip_value]
                else:
                    dps_client_domain = domain.DPSClients_Hash_IPv6[self.location.ip_value]
                dps_client_domain.delete()
            except Exception:
                continue
        self.domains.clear()
        try:
            del DPSClientHost.Collection[self.location.ip_value]
        except Exception:
            pass
        return

    @staticmethod
    def Host_Add(domain, ip_type, ip_val, port, client_type):
        '''
        This is the routine calling routines should invoke to add a DPS Client
        to the collection
        @attention: This routine must be called with the global lock held
        @param domain: The Domain object
        @type domain: Domain
        @param ip_type: socket.AF_INET6 or socket.AF_INET
        @type ip_type: Integer
        @param ip_val: The Value of the IP Address
        @type ip_val: String (IPv6) or Integer
        @param port: The DPS Client Port (for UDP communication)
        @type port: Integer
        @param client_type: What kind of Client is it
        @type client_type: Should be one of DpsClientType
        '''
        #print 'Host_Add: Enter\r'
        try:
            dps_client = DPSClientHost.Collection[ip_val]
            dps_client.update_add(domain, port, client_type)
        except Exception:
            dps_client = DPSClientHost(domain, ip_type, ip_val, port, client_type)
        #print 'Host_Add: Exit\r'
        return

    @staticmethod
    def Host_Delete(domain, ip_val, client_type):
        '''
        This is the routine calling routines should invoke to add a DPS Client
        to the collection
        @attention: This routine must be called with the global lock held
        @param domain: The Domain object
        @type domain: Domain
        @param ip_val: The Value of the IP Address
        @type ip_val: String (IPv6) or Integer
        @param client_type: What kind of Client is it
        @type client_type: Should be one of DpsClientType
        '''
        try:
            dps_client = DPSClientHost.Collection[ip_val]
            dps_client.update_delete(domain, client_type)
        except Exception:
            pass
        return

    @staticmethod
    def Host_Delete_All(domain, ip_val):
        '''
        This is the routine calling routines should invoke to add a DPS Client
        to the collection
        @attention: This routine must be called with the global lock held
        @param domain: The Domain object
        @type domain: Domain
        @param ip_val: The Value of the IP Address
        @type ip_val: String (IPv6) or Integer
        '''
        try:
            dps_client = DPSClientHost.Collection[ip_val]
            dps_client.delete()
        except Exception:
            pass
        return

    @staticmethod
    def Host_Touch(ip_val, port):
        '''
        This routine touches the Host
        @param ip_val: The value
        @param port: The port of the DPS Client
        '''
        try:
            dps_client = DPSClientHost.Collection[ip_val]
            if port != 0:
                dps_client.location.port = port
            dps_client.touch()
        except Exception:
            pass
        return

    @staticmethod
    def Domain_Deleted_Locally(domain):
        '''
        This routine should be called when a domain is deleted or de-activated
        from the local DCS Server Node
        @attention: This routine must be called with the global lock held
        @param domain: The Domain object
        @type domain: Domain
        '''
        try:
            dps_clients = DPSClientHost.Collection.values()
            for dps_client in dps_clients:
                try:
                    dps_client.domain_delete(domain)
                except Exception:
                    pass
        except Exception:
            pass
        return

    @staticmethod
    def Send_Heartbeat():
        '''
        This routine sends Heartbeats to all DPS Client which have not been
        contacted for the specified amount of time. 
        '''
        curr_time = time.time()
        try:
            dps_clients = DPSClientHost.Collection.values()
            for dps_client in dps_clients:
                try:
                    time_diff = int(curr_time - dps_client.last_contact)
                    client_type = dps_client.client_type
                    time_no_contact = DPSClientHost.heartbeat_no_contact[client_type]
                    time_heartbeat_send = DPSClientHost.heartbeat_frequency[client_type]
                    if time_diff > time_no_contact:
                        print 'No contact from DPS Client %s for %s seconds. Deleting!!!\r'%(dps_client.location.show_ip(),
                                                                                             time_diff)
                        dps_client.delete()
                    elif time_diff >= time_heartbeat_send:
                        vnid = dps_client.vnid_random_get()
                        query_id = DpsCollection.generate_query_id()
                        dcslib.send_heartbeat(dps_client.location.ip_value_packed,
                                              dps_client.location.port,
                                              vnid, query_id)
                except Exception:
                    continue
        except Exception:
            pass
        return

    @staticmethod
    def show():
        curr_time = time.time()
        print '%s %s\r'%('DCS Clients'.rjust(20), 'Age Time'.rjust(20))
        try:
            dps_clients = DPSClientHost.Collection.values()
            for dps_client in dps_clients:
                time_diff = int(curr_time - dps_client.last_contact)
                print '%s %s\r'%(dps_client.location.show_ip().rjust(20),str(time_diff).rjust(20))
        except Exception:
            pass
        return