Exemplo n.º 1
0
class Switch(Device):
    """\brief Superclass for any switch in the testbed
    This class implements methods to retrieve information from a switch using SNMP version 1. In
    addition, it acts as a super class for all types of switches in the testbed
    """
    functions = []
    mask = [128,64,32,16,8,4,2,1,0]
    inv_mask = [127,191,223,239,247,251,254,255]

    def __init__(self, switchNode, minimumVLANInternalID, maximumVLANInternalID, minimumInterfaceInternalID, maximumInterfaceInternalID):
        """\brief Initializes the class
        \param switchNode (\c SwitchNode) The SwitchNode object to obtain information from to initialize the class with
        \param macIDLength (\c int) The length of the id of an snmp result coming from a mac address query. The id is
                                    anything to the left of the equal sign, and its length is the number of dot-separated
                                    terms.
        """
        if (switchNode.getInfrastructure() == "yes"):
            self.__ipAddress = switchNode.getInterfaces("infrastructure")[0].getIP()
        else:
            self.__ipAddress = switchNode.getInterfaces("management")[0].getIP()

        self.__switchName = switchNode.getNodeID()
        self.snmp = SNMP(switchNode.getSNMPwriteCommunity(),self.__ipAddress)

        # cache of static tables
        self.__refresh = True # reload
        self.__dot1dBasePortIfIndex = None
        self.__ifDescr = None
        self.__ifName = None
        self.__dot1qVlanStaticUntaggedPorts = None
        self.__dot1qVlanStaticEgressPorts = None
        self.__dot1qPvid = None
        self.__dot1qTpFdbPort = None
        self.__dot1qTpFdbStatus = None
        self.__dot1qVlanFdbId = None
        self.__dot1qVlanStaticName = None
        
        # ports
        self.__ports = {}
        self.refreshPortInfo()
        # vlans
        self.__vlans = {}
        
# Informational commands
            
    def getSwitchName(self,use_snmp=False):
        """\brief Retrieves the switch's name
        \param use_snmp (\c boolean) if True read value from switch.
        \return (\c string) The switch's name
        """

        if use_snmp:
            return self.snmp.get(OID.sysName)[0][1]
        else:
            return self.__switchName
        
    def setSwitchName(self,name,commit=False):
        """\brief Sets the switch's name, and commits to the hardware if commit is True
        \param name (\c string) The switch's name
        \param commit (\c boolean) If True apply to hardware
        \return (\c int) Returns 0 if successful, -1 if unsuccessful
        """
        self.__switchName = name
        if commit:
            self.snmp.set(OID.sysName,rfc1902.OctetString(name))
            return self.snmp.getErrorStatus()
        return

    def getPorts(self):
        return self.__ports

    def getPort(self,local_id):
        return self.__ports[local_id]

    def getPortByName(self,i):
        for port in self.__ports:
            if str(self.__ports[port].getName()) == str(i):
                return self.__ports[port]
        return None
    
    def addPort(self,port):
        self.__ports[port.getId()] = port

    def clearPorts(self):
        self.__ports = {}

    def resetPortsVlanInfo(self):
        for port in self.__ports:
            self.__ports[port].setUntagged((None,None))
            self.__ports[port].setPvid((None,None))
            self.__ports[port].setTagged([])

    def resetPortsMacInfo(self):
        for port in self.__ports:
            self.__ports[port].setMacs([])

    def getPortsVlanMode(self):
        return None

    def getPortVlanMode(self,pid):
        return 0
    
    def setPortVlanMode(self,pid,mode):
        return 0
                    
    
    def refreshPortInfo(self):
        """\brief Refreshes the port list for the switch`
        """
        self.clearPorts()
        #log.debug("Creating ports")
        ifname_table = self.getPortNames()
        iftype_table = self.snmp.walk(OID.ifType)
        portsvlanmode_table = self.getPortsVlanMode()
        
        ethernet_ports = []
        for iftype in iftype_table:
            if str(iftype[0][1]) == "6":
                ethernet_ports.append(iftype[0][0][-1])
        
        for ifname in ifname_table:
            if int(ifname[0][0][-1]) in ethernet_ports:
                sp = SimplePort(ifname[0][1],ifname[0][0][-1],self.getNodeID())
                self.addPort(sp)

        if portsvlanmode_table != None:
            for portmode in portsvlanmode_table:
                sp = self.getPort(portmode[0][0][-1])
                sp.setVlanMode(int(portmode[0][1]))
                
    def getVlans(self):
        return self.__vlans

    def getVlan(self,ident):
        return self.__vlans[ident]

    def getVlanByName(self,name):
        for v_id in self.__vlans:
            if str(self.__vlans[v_id].getName()) == name:
                log.debug("Vlan name "+str(name)+" id "+str(v_id)+" "+str(self.__vlans[v_id]))
                return self.__vlans[v_id]
        return None
    
    def addVlan(self,vlan):
        self.__vlans[vlan.getLocalId()] = vlan

    def clearVlans(self):
        self.__vlans = {}

    def getNodeID(self):
        return self.__switchName
    
    def setIPAddress(self, i):
        """\brief Sets the ip address of the switch's management interface and updates the snmp command accordingly
        \param i (\c string) The ip address of the switch's management interface
        """
        self.__ipAddress = i
        self.snmp.setIpAddress(i)

    def getIPAddress(self):
        """\brief Gets the ip address of the switch's management interface
        \return (\c string) The ip address of the switch's management interface
        """ 
        return self.__ipAddress

    def getNumberofPorts(self):
        """\brief Retrieves the number of ports on the switch
        \return (\c string) The number of ports on the switch
        """
        return self.snmp.get(OID.dot1dBaseNumPorts)[0][1]

    def getSwitchDescription(self):
        """\brief Retrieves the switch's description
        \return (\c string) The switch's description
        """
        return self.snmp.get(OID.sysDescr)[0][1]

    def setSwitchDescription(self,s):
        """\brief Retrieves the switch's description
        \return (\c int) Returns 0 if successful, -1 if unsuccessful
        """
        self.snmp.set(OID.sysDescr,rfc1902.OctetString(s))
        return self.snmp.getErrorStatus()

    def getSwitchUptime(self):
        """\brief Retrieves the switch's uptime
        \return (\c string) The switch's uptime
        """
        return str(self.snmp.get(OID.sysUpTimeInstance)[0][1])
    
    def getSwitchContact(self):
        """\brief Retrieves the switch's contact
        \return (\c string) The switch's contact
        """
        return self.snmp.get(OID.sysContact)[0][1]

    def setSwitchContact(self,s):
        """\brief Retrieves the switch's contact
        \param s (\c string) The switch's contact
        \return (\c int) Returns 0 if successful, -1 if unsuccessful
        """
        self.snmp.set(OID.sysContact,rfc1902.OctetString(s))
        return self.snmp.getErrorStatus()

    def getSwitchLocation(self):
        """\brief Retrieves the switch's location
        \return (\c string) The switch's location
        """
        return self.snmp.get(OID.sysLocation)[0][1]
    
    def setSwitchLocation(self,s):
        """\brief Retrieves the switch's location
        \param s (\c string) The switch's location
        \return (\c int) Returns 0 if successful, -1 if unsuccessful
        """
        self.snmp.set(OID.sysLocation,rfc1902.OctetString(s))
        return self.snmp.getErrorStatus()

    def getSerialNumber(self):
        """\brief returns the serial number of the device 
        \return A string of the serial number
        """
        return ""

# operational commands

## Ports

    def enablePort(self, portNumber):
        """\brief Enables a port. Returns 0 upon success, -1 otherwise
        \param portNumber (\c string) The port to enable
        \return (\c int) 0 if succesful, -1 otherwise
        """
        internalID = int(self.getPortInternalID(portNumber))
        self.snmp.set(OID.ifAdminStatus+(internalID,),rfc1902.Integer(1))
        return self.snmp.getErrorStatus()

    def getPortStatus(self, portNumber):
        """\brief Gets the operational status of a port: up (1), down (2) 
        \param portNumber (\c string) The port whose status is to be retrieved
        \return (\c string) The port status
        """
        internalID = int(self.getPortInternalID(portNumber))
        return self.snmp.get(OID.ifOperStatus+(internalID,))[0][1]


    def getPortAdminStatus(self, portNumber):
        """\brief Gets the status of a port: up (1), down (2) or testing (3)
        \param portNumber (\c string) The port whose status is to be retrieved
        \return (\c string) The port status
        """
        internalID = int(self.getPortInternalID(portNumber))
        return self.snmp.get(OID.ifAdminStatus+(internalID,))[0][1]

    def disablePort(self, portNumber):
        """\brief Disables a port. Returns 0 upon success, -1 otherwise
        \param portNumber (\c string) The port to disable
        \return (\c int) 0 if succesful, -1 otherwise
        """
        internalID = int(self.getPortInternalID(portNumber))
        self.snmp.set(OID.ifAdminStatus+(internalID,),rfc1902.Integer(2))
        return self.snmp.getErrorStatus()
             
    def getPortIDs(self):
        """\brief Gets the internal ids for each of the ports on the switch. This function
                  returns a dictionary with the results
        \return (\c dictionary) A dictionary with the results (see getSNMPResultTable for more information)
        """
        return self.getDot1dBasePortIfIndex()

    def getPortNames(self):
        if self.__ifName == None:
            self.__ifName = self.snmp.walk(OID.ifName)
        return self.__ifName

    def getDot1dBasePortIfIndex(self):
        if self.__dot1dBasePortIfIndex == None:
            self.__dot1dBasePortIfIndex = self.snmp.walk(OID.dot1dBasePortIfIndex)
        return self.__dot1dBasePortIfIndex

    def getIfDescr(self):
        if self.__ifDescr == None:
            self.__ifDescr = self.snmp.walk(OID.ifDescr)
        return self.__ifDescr
                            

    def getPortInternalID(self, portNumber):
        """\brief Given a port's external number, this function returns its internal
                  number. If the port is not found -1 is returned
        \param portNumber (\c string) The port number whose internal port is to be searched
        \return (\c string) The port's internal id, or -1 if unsuccessful
        """
        varBindTable = self.getPortIDs()
        for tableRow in varBindTable:
            for name, val in tableRow:
                #print name,val
                if name is None:
                    continue
                if name[len(name)-1] == rfc1902.Integer32(portNumber):
                    return val 
        return -1

    def getFullMACTable(self):
        """\brief Gets the full learned mac table from the switch, returning a list of MACTableEntry objects.
        \return (\c list) A list of MACTableEntry objects with the results.
        """
        portsTable = self.snmp.walk(OID.dot1dTpFdbPort)
        learnedTypeTable = self.snmp.walk(OID.dot1dTpFdbStatus)

        result = []

        for learnedTypeTableRow in learnedTypeTable:
            for learnedname, learnedval in learnedTypeTableRow:
                if learnedval == rfc1902.Integer32('3'):
                    learnedname = rfc1902.ObjectName((learnedname.prettyPrint()).replace(OID.dot1dTpFdbStatus.prettyPrint(),OID.dot1dTpFdbPort.prettyPrint()))
                    for portTableRow in portsTable:
                        for portname, portval in portTableRow:
                            if learnedname == portname:
                                result.append(MACTableEntry(("%02x:%02x:%02x:%02x:%02x:%02x" % (int(learnedname[11]),int(learnedname[12]),int(learnedname[13]),int(learnedname[14]),int(learnedname[15]),int(learnedname[16]))).replace("0x","").upper(),portval,'3',self.__switchName))
                                
        return result

        for key in learnedTypeTable.keys():
            if (learnedTypeTable[key] == str(3)):
                mac = MACTableEntry((macAddressesTable[key]).replace(' ',':',5).upper(),portsTable[key],learnedTypeTable[key])
                mac.setSwitch(self.getSwitchID())
                result.append(mac)
                #print mac

    def getInterfaceDescriptionTable(self):
        """\brief Gets the table of interface descriptions
        \return (\c dictionary) A dictionary with the results (see getSNMPResultTable for more information)
        """
        result = {}
        interfaceTable = self.getIfDescr()
        for interfaceTableRow in interfaceTable:
            for name, val in interfaceTableRow:
                result[name[len(name)-1]] = val

        return result

    def setCommunity(self, c):
        """\brief Sets the community and updates the snmp commands accordingly
        \param c (\c string) The community
        """
        self.snmp.setCommunity(c)


    def getCommunity(self):
        """\brief Gets the community
        \return (\c string) The community
        """
        return self.snmp.getCommunity()

## VLANS

    def getVLANToInterfacesTable(self):
        """\brief Gets the mappings between VLANS and interfaces (ports)
        \return (\c dictionary) A dictionary with the results (see getSNMPResultVLANTable for more information)
        """
        table = {}
        ifStackStatusTable = self.snmp.walk(OID.ifStackStatus)
        for ifStackStatusTableRow in ifStackStatusTable:
            if (table.has_key(ifStackStatusTableRow[0][0][len(ifStackStatusTableRow[0][0])-2]) == False):
                table[ifStackStatusTableRow[0][0][len(ifStackStatusTableRow[0][0])-2]] = []
            table[ifStackStatusTableRow[0][0][len(ifStackStatusTableRow[0][0])-2]].append(ifStackStatusTableRow[0][0][len(ifStackStatusTableRow[0][0])-1])
        return table

    def getVlanInfo(self):
        vlans = {}
        dot1qVlanStaticNameTable = self.snmp.walk(OID.dot1qVlanStaticName)
        dot1qVlanFdbIdTable = self.snmp.walk(OID.dot1qVlanFdbId)
        
        for dot1qVlanStaticNameTableRow in dot1qVlanStaticNameTable:
            for dot1qVlanFdbIdTableRow in dot1qVlanFdbIdTable:
                if dot1qVlanStaticNameTableRow[0][0][len(dot1qVlanStaticNameTableRow[0][0])-1] == dot1qVlanFdbIdTableRow[0][0][len(dot1qVlanFdbIdTableRow[0][0])-1] :
                    
                    vlans[dot1qVlanStaticNameTableRow[0][1]]  = (int(dot1qVlanFdbIdTableRow[0][1]),dot1qVlanStaticNameTableRow[0][0][len(dot1qVlanStaticNameTableRow[0][0])-1])

        return vlans
        
    def setMinimumVLANInternalID(self, m):
        print "not implemented"
        
    def getMinimumVLANInternalID(self):
        print "not implemented"

    def setMaximumVLANInternalID(self, m):
        print "not implemented"

    def getMaximumVLANInternalID(self):
        print "not implemented"

    def getVLANNames(self):
        print "not implemented"

    def getFullVLANInfo(self, theVLANName=None):
        print "not implemented"

    def createVLAN(self, vlan):
        print "not implemented"
                    
    def addPorts(self, vlanName, ports):
        print "not implemented"

    def deletePorts(self, vlanName, ports):
        print "not implemented"
                
    def deleteVLAN(self, vlanName):
        print "not implemented"
                
    def populateVLAN(self, vlanName):
        print "not implemented"        

    def getEmptyBitMap(self,num_ports=None):
        s = ""
        if num_ports == None:
            num_ports = int(self.snmp.get(OID.dot1dBaseNumPorts)[0][1])

        for i in range(0,divmod(num_ports,8)[0]):
            s = s + pack('B',0)
        return s
                                                
    def printPortMap(self, portList, Tagged=False):

        bitfield = array('B')
        
        for i in range(0,len(portList)):
            bitfield.extend(unpack('B',portList[i]))
                 
        s = "u"
        if Tagged:
            s = "t"
        for port in bitfield:
            for slot in range(0,8):
                if slot == 0:
                    s = s + " "
                if (port & Switch.mask[slot] == Switch.mask[slot]):
                    s = s + "1"
                else:
                    s = s + "0"
        return s

    def getPortTdr(self, port_str):
        return (False,"TDR testing not supported")

####
# Caching code
####

    def getDot1qVlanStaticUntaggedPorts(self,run=False):
        if self.__dot1qVlanStaticUntaggedPorts == None or self.__refresh or run:
            self.__dot1qVlanStaticUntaggedPorts = self.snmp.walk(OID.dot1qVlanStaticUntaggedPorts)
        return self.__dot1qVlanStaticUntaggedPorts

    def getDot1qVlanStaticEgressPorts(self,run=False):
        if self.__dot1qVlanStaticEgressPorts == None or self.__refresh or run:
            self.__dot1qVlanStaticEgressPorts = self.snmp.walk(OID.dot1qVlanStaticEgressPorts)
        return self.__dot1qVlanStaticEgressPorts

    def getDot1qPvid(self,run=False):
        if self.__dot1qPvid == None or self.__refresh or run:
            self.__dot1qPvid = self.snmp.walk(OID.dot1qPvid)
        return self.__dot1qPvid

    def getDot1qTpFdbPort(self,run=False):
        if self.__dot1qTpFdbPort == None or self.__refresh or run:
            self.__dot1qTpFdbPort = self.snmp.walk(OID.dot1qTpFdbPort)
        return self.__dot1qTpFdbPort

    def getDot1qTpFdbStatus(self,run=False):
        if self.__dot1qTpFdbStatus == None or self.__refresh or run:
            self.__dot1qTpFdbStatus = self.snmp.walk(OID.dot1qTpFdbStatus)
        return self.__dot1qTpFdbStatus

    def getDot1qVlanStaticName(self,run=False):
        if self.__dot1qVlanStaticName == None or self.__refresh or run:
            self.__dot1qVlanStaticName = self.snmp.walk(OID.dot1qVlanStaticName)
        return self.__dot1qVlanStaticName

    def getDot1qVlanFdbId(self,run=False):
        if self.__dot1qVlanFdbId == None or self.__refresh or run:
            self.__dot1qVlanFdbId = self.snmp.walk(OID.dot1qVlanFdbId)
        return self.__dot1qVlanFdbId