Exemple #1
0
    def _update_entity_cache(self, interface):
        """
        Update data for single transceiver
        :param: interface: Interface name associated with transceiver
        """

        # get interface from interface name
        ifindex = port_util.get_index_from_str(interface)

        if ifindex is None:
            # interface name invalid, skip this entry
            mibs.logger.warning("Invalid interface name in {} \
                 in STATE_DB, skipping".format(interface))
            return

        # get transceiver information from transceiver info entry in STATE DB
        transceiver_info = Namespace.dbs_get_all(
            self.mib_updater.statedb, mibs.STATE_DB,
            mibs.transceiver_info_table(interface))

        if not transceiver_info:
            return

        # update xcvr info from DB
        # use port's name as key for transceiver info entries
        sub_id = get_transceiver_sub_id(ifindex)

        # add interface to available OID list
        self.mib_updater.add_sub_id(sub_id)

        self._add_entity_related_oid(interface, sub_id)

        # physical class - network port
        self.mib_updater.set_phy_class(sub_id, PhysicalClass.PORT)

        # save values into cache
        sfp_type, hw_version, serial_number, mfg_name, model_name, replaceable = get_db_data(
            transceiver_info, XcvrInfoDB)
        self.mib_updater.set_phy_hw_ver(sub_id, hw_version)
        self.mib_updater.set_phy_serial_num(sub_id, serial_number)
        self.mib_updater.set_phy_mfg_name(sub_id, mfg_name)
        self.mib_updater.set_phy_model_name(sub_id, model_name)
        self.mib_updater.set_phy_contained_in(sub_id, CHASSIS_SUB_ID)
        self.mib_updater.set_phy_fru(sub_id, replaceable)
        # Relative position of SFP can be changed at run time. For example, plug out a normal cable SFP3 and plug in
        # a 1 split 4 SFP, the relative position of SFPs after SPF3 will change. In this case, it is hard to determine
        # the relative position for other SFP. According to RFC 2737, 'If the agent cannot determine the parent-relative position
        # for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned'.
        # See https://tools.ietf.org/html/rfc2737.
        self.mib_updater.set_phy_parent_relative_pos(sub_id, -1)

        ifalias = self.if_alias_map.get(interface, "")

        # generate a description for this transceiver
        self.mib_updater.set_phy_descr(
            sub_id, get_transceiver_description(sfp_type, ifalias))
        self.mib_updater.set_phy_name(sub_id, interface)

        # update transceiver sensor cache
        self._update_transceiver_sensor_cache(interface, sub_id)
Exemple #2
0
    def _update_transceiver_cache(self, interface):
        """
        Update data for single transceiver
        :param: interface: Interface name associated with transceiver
        """

        # get interface from interface name
        ifindex = port_util.get_index_from_str(interface)

        # update xcvr info from DB
        # use port's name as key for transceiver info entries
        sub_id = mibs.get_transceiver_sub_id(ifindex)

        # add interface to available OID list
        insort_right(self.physical_entities, sub_id)

        # get transceiver information from transceiver info entry in STATE DB
        transceiver_info = Namespace.dbs_get_all(
            self.statedb, mibs.STATE_DB,
            mibs.transceiver_info_table(interface))

        if not transceiver_info:
            return

        # physical class - network port
        self.physical_classes_map[sub_id] = PhysicalClass.PORT

        # save values into cache
        sfp_type, \
        self.physical_hw_version_map[sub_id],\
        self.physical_serial_number_map[sub_id], \
        self.physical_mfg_name_map[sub_id], \
        self.physical_model_name_map[sub_id] = get_transceiver_data(transceiver_info)

        ifalias = self.if_alias_map.get(interface.encode(), b"").decode()

        # generate a description for this transceiver
        self.physical_description_map[sub_id] = get_transceiver_description(
            sfp_type, ifalias)

        # update transceiver sensor cache
        self._update_transceiver_sensor_cache(interface)
Exemple #3
0
class XcvrCacheUpdater(PhysicalEntityCacheUpdater):
    KEY_PATTERN = mibs.transceiver_info_table("*")

    def __init__(self, mib_updater):
        super(XcvrCacheUpdater, self).__init__(mib_updater)
        self.if_alias_map = {}

    def get_key_pattern(self):
        return XcvrCacheUpdater.KEY_PATTERN

    def reinit_data(self):
        # update interface maps
        _, self.if_alias_map, _, _ = \
            Namespace.get_sync_d_from_all_namespace(mibs.init_sync_d_interface_tables, Namespace.init_namespace_dbs())
        PhysicalEntityCacheUpdater.reinit_data(self)

    def _update_entity_cache(self, interface):
        """
        Update data for single transceiver
        :param: interface: Interface name associated with transceiver
        """

        # get interface from interface name
        ifindex = port_util.get_index_from_str(interface)

        if ifindex is None:
            # interface name invalid, skip this entry
            mibs.logger.warning("Invalid interface name in {} \
                 in STATE_DB, skipping".format(interface))
            return

        # get transceiver information from transceiver info entry in STATE DB
        transceiver_info = Namespace.dbs_get_all(
            self.mib_updater.statedb, mibs.STATE_DB,
            mibs.transceiver_info_table(interface))

        if not transceiver_info:
            return

        # update xcvr info from DB
        # use port's name as key for transceiver info entries
        sub_id = get_transceiver_sub_id(ifindex)

        # add interface to available OID list
        self.mib_updater.add_sub_id(sub_id)

        self._add_entity_related_oid(interface, sub_id)

        # physical class - network port
        self.mib_updater.set_phy_class(sub_id, PhysicalClass.PORT)

        # save values into cache
        sfp_type, hw_version, serial_number, mfg_name, model_name, replaceable = get_db_data(
            transceiver_info, XcvrInfoDB)
        self.mib_updater.set_phy_hw_ver(sub_id, hw_version)
        self.mib_updater.set_phy_serial_num(sub_id, serial_number)
        self.mib_updater.set_phy_mfg_name(sub_id, mfg_name)
        self.mib_updater.set_phy_model_name(sub_id, model_name)
        self.mib_updater.set_phy_contained_in(sub_id, CHASSIS_SUB_ID)
        self.mib_updater.set_phy_fru(sub_id, replaceable)
        # Relative position of SFP can be changed at run time. For example, plug out a normal cable SFP3 and plug in
        # a 1 split 4 SFP, the relative position of SFPs after SPF3 will change. In this case, it is hard to determine
        # the relative position for other SFP. According to RFC 2737, 'If the agent cannot determine the parent-relative position
        # for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned'.
        # See https://tools.ietf.org/html/rfc2737.
        self.mib_updater.set_phy_parent_relative_pos(sub_id, -1)

        ifalias = self.if_alias_map.get(interface, "")

        # generate a description for this transceiver
        self.mib_updater.set_phy_descr(
            sub_id, get_transceiver_description(sfp_type, ifalias))
        self.mib_updater.set_phy_name(sub_id, interface)

        # update transceiver sensor cache
        self._update_transceiver_sensor_cache(interface, sub_id)

    def _update_transceiver_sensor_cache(self, interface, sub_id):
        """
        Update sensor data for single transceiver
        :param: interface: Interface name associated with transceiver
        :param: sub_id: OID of transceiver
        """

        ifalias = self.if_alias_map.get(interface, "")
        ifindex = port_util.get_index_from_str(interface)

        # get transceiver sensors from transceiver dom entry in STATE DB
        transceiver_dom_entry = Namespace.dbs_get_all(
            self.mib_updater.statedb, mibs.STATE_DB,
            mibs.transceiver_dom_table(interface))

        if not transceiver_dom_entry:
            return

        # go over transceiver sensors
        for sensor in transceiver_dom_entry:
            if sensor not in XCVR_SENSOR_NAME_MAP:
                continue
            sensor_sub_id = get_transceiver_sensor_sub_id(ifindex, sensor)
            self._add_entity_related_oid(interface, sensor_sub_id)
            sensor_description = get_transceiver_sensor_description(
                sensor, ifalias)

            self.mib_updater.set_phy_class(sensor_sub_id, PhysicalClass.SENSOR)
            self.mib_updater.set_phy_descr(sensor_sub_id, sensor_description)
            self.mib_updater.set_phy_name(sensor_sub_id, sensor_description)
            self.mib_updater.set_phy_contained_in(sensor_sub_id, sub_id)
            self.mib_updater.set_phy_parent_relative_pos(
                sensor_sub_id, XCVR_SENSOR_INDEX_MAP[sensor])
            self.mib_updater.set_phy_fru(sensor_sub_id, False)
            # add to available OIDs list
            self.mib_updater.add_sub_id(sensor_sub_id)
Exemple #4
0
class PhysicalTableMIBUpdater(MIBUpdater):
    """
    Updater class for physical table MIB
    """

    CHASSIS_ID = 1
    TRANSCEIVER_KEY_PATTERN = mibs.transceiver_info_table("*")

    def __init__(self):
        super().__init__()

        self.statedb = Namespace.init_namespace_dbs()
        Namespace.connect_all_dbs(self.statedb, mibs.STATE_DB)

        self.if_alias_map = {}

        # List of available sub OIDs.
        self.physical_entities = []

        # Map sub ID to its data.
        self.physical_classes_map = {}
        self.physical_description_map = {}
        self.physical_hw_version_map = {}
        self.physical_serial_number_map = {}
        self.physical_mfg_name_map = {}
        self.physical_model_name_map = {}

        self.pubsub = [None] * len(self.statedb)

    def reinit_data(self):
        """
        Re-initialize all data.
        """

        # reinit cache
        self.physical_classes_map = {}
        self.physical_description_map = {}
        self.physical_hw_version_map = {}
        self.physical_serial_number_map = {}
        self.physical_mfg_name_map = {}
        self.physical_model_name_map = {}

        # update interface maps
        _, self.if_alias_map, _, _, _ = \
            Namespace.init_namespace_sync_d_interface_tables(Namespace.init_namespace_dbs())

        device_metadata = mibs.get_device_metadata(self.statedb[0])
        chassis_sub_id = (self.CHASSIS_ID, )
        self.physical_entities = [chassis_sub_id]

        if not device_metadata or not device_metadata.get(b"chassis_serial_number"):
            chassis_serial_number = ""
        else:
            chassis_serial_number = device_metadata[b"chassis_serial_number"]

        self.physical_classes_map[chassis_sub_id] = PhysicalClass.CHASSIS
        self.physical_serial_number_map[chassis_sub_id] = chassis_serial_number

        # retrieve the initial list of transceivers that are present in the system
        transceiver_info = Namespace.dbs_keys(self.statedb, mibs.STATE_DB, self.TRANSCEIVER_KEY_PATTERN)
        if transceiver_info:
            self.transceiver_entries = [entry.decode() \
                for entry in transceiver_info]
        else:
            self.transceiver_entries = []

        # update cache with initial data
        for transceiver_entry in self.transceiver_entries:
            # extract interface name
            interface = transceiver_entry.split(mibs.TABLE_NAME_SEPARATOR_VBAR)[-1]
            self._update_transceiver_cache(interface)

    def _update_per_namespace_data(self, pubsub):
        """
        Update cache.
        Here we listen to changes in STATE_DB TRANSCEIVER_INFO table
        and update data only when there is a change (SET, DELETE)
        """

        # This code is not executed in unit test, since mockredis
        # does not support pubsub
        while True:
            msg = pubsub.get_message()

            if not msg:
                break

            transceiver_entry = msg["channel"].split(b":")[-1].decode()
            data = msg['data'] # event data

            # extract interface name
            interface = transceiver_entry.split(mibs.TABLE_NAME_SEPARATOR_VBAR)[-1]

            # get interface from interface name
            ifindex = port_util.get_index_from_str(interface)

            if ifindex is None:
                # interface name invalid, skip this entry
                mibs.logger.warning(
                    "Invalid interface name in {} \
                     in STATE_DB, skipping".format(transceiver_entry))
                continue

            if b"set" in data:
                self._update_transceiver_cache(interface)
            elif b"del" in data:
                # remove deleted transceiver
                remove_sub_ids = [mibs.get_transceiver_sub_id(ifindex)]

                # remove all sensor OIDs associated with removed transceiver
                for sensor in SENSOR_NAME_MAP:
                    remove_sub_ids.append(mibs.get_transceiver_sensor_sub_id(ifindex, sensor))

                for sub_id in remove_sub_ids:
                    if sub_id and sub_id in self.physical_entities:
                        self.physical_entities.remove(sub_id)

    def update_data(self):
        # This code is not executed in unit test, since mockredis
        # does not support pubsub
        for i in range(len(self.statedb)):
            if not self.pubsub[i]:
                pattern = self.TRANSCEIVER_KEY_PATTERN
                self.pubsub[i] = mibs.get_redis_pubsub(self.statedb[i], self.statedb[i].STATE_DB, pattern)
            self._update_per_namespace_data(self.pubsub[i])

    def _update_transceiver_cache(self, interface):
        """
        Update data for single transceiver
        :param: interface: Interface name associated with transceiver
        """

        # get interface from interface name
        ifindex = port_util.get_index_from_str(interface)

        # update xcvr info from DB
        # use port's name as key for transceiver info entries
        sub_id = mibs.get_transceiver_sub_id(ifindex)

        # add interface to available OID list
        insort_right(self.physical_entities, sub_id)

        # get transceiver information from transceiver info entry in STATE DB
        transceiver_info = Namespace.dbs_get_all(self.statedb, mibs.STATE_DB,
                                                mibs.transceiver_info_table(interface))

        if not transceiver_info:
            return

        # physical class - network port
        self.physical_classes_map[sub_id] = PhysicalClass.PORT

        # save values into cache
        sfp_type, \
        self.physical_hw_version_map[sub_id],\
        self.physical_serial_number_map[sub_id], \
        self.physical_mfg_name_map[sub_id], \
        self.physical_model_name_map[sub_id] = get_transceiver_data(transceiver_info)

        ifalias = self.if_alias_map.get(interface.encode(), b"").decode()

        # generate a description for this transceiver
        self.physical_description_map[sub_id] = get_transceiver_description(sfp_type, ifalias)

        # update transceiver sensor cache
        self._update_transceiver_sensor_cache(interface)

    def _update_transceiver_sensor_cache(self, interface):
        """
        Update sensor data for single transceiver
        :param: interface: Interface name associated with transceiver
        """

        ifalias = self.if_alias_map.get(interface.encode(), b"").decode()
        ifindex = port_util.get_index_from_str(interface)

        # get transceiver sensors from transceiver dom entry in STATE DB
        transceiver_dom_entry = Namespace.dbs_get_all(self.statedb, mibs.STATE_DB,
                                                     mibs.transceiver_dom_table(interface))

        if not transceiver_dom_entry:
            return

        # go over transceiver sensors
        for sensor in map(bytes.decode, transceiver_dom_entry):
            if sensor not in SENSOR_NAME_MAP:
                continue
            sensor_sub_id = mibs.get_transceiver_sensor_sub_id(ifindex, sensor)
            sensor_description = get_transceiver_sensor_description(sensor, ifalias)

            self.physical_classes_map[sensor_sub_id] = PhysicalClass.SENSOR
            self.physical_description_map[sensor_sub_id] = sensor_description

            # add to available OIDs list
            insort_right(self.physical_entities, sensor_sub_id)

    def get_next(self, sub_id):
        """
        :param sub_id: The 1-based sub-identifier query.
        :return: the next sub id.
        """

        right = bisect_right(self.physical_entities, sub_id)
        if right == len(self.physical_entities):
            return None
        return self.physical_entities[right]

    def get_phy_class(self, sub_id):
        """
        :param sub_id: sub OID
        :return: physical class for this OID
        """

        if sub_id in self.physical_entities:
            return self.physical_classes_map.get(sub_id, PhysicalClass.UNKNOWN)
        return None

    def get_phy_descr(self, sub_id):
        """
        :param sub_id: sub OID
        :return: description string for this OID
        """

        if sub_id in self.physical_entities:
            return self.physical_description_map.get(sub_id, "")
        return None

    def get_phy_name(self, sub_id):
        """
        :param sub_id: sub OID
        :return: name string for this OID
        """

        return "" if sub_id in self.physical_entities else None

    def get_phy_hw_ver(self, sub_id):
        """
        :param sub_id: sub OID
        :return: hardware version for this OID
        """

        if sub_id in self.physical_entities:
            return self.physical_hw_version_map.get(sub_id, "")
        return None

    def get_phy_fw_ver(self, sub_id):
        """
        :param sub_id: sub OID
        :return: firmware version for this OID
        """

        return "" if sub_id in self.physical_entities else None

    def get_phy_sw_rev(self, sub_id):
        """
        :param sub_id: sub OID
        :return: software version for this OID
        """

        return "" if sub_id in self.physical_entities else None

    def get_phy_serial_num(self, sub_id):
        """
        :param sub_id: sub OID
        :return: serial number for this OID
        """

        if sub_id in self.physical_entities:
            return self.physical_serial_number_map.get(sub_id, "")
        return None

    def get_phy_mfg_name(self, sub_id):
        """
        :param sub_id: sub OID
        :return: manufacture name for this OID
        """

        if sub_id in self.physical_entities:
            return self.physical_mfg_name_map.get(sub_id, "")
        return None

    def get_phy_model_name(self, sub_id):
        """
        :param sub_id: sub OID
        :return: model name for this OID
        """

        if sub_id in self.physical_entities:
            return self.physical_model_name_map.get(sub_id, "")
        return None