コード例 #1
0
    def check_power(self, ipmi_server, node_id):
        power_states = self.client.get_power_state(ipmi_server)

        cluster_name = self._cfg.clusters[0].name
        node_name = cluster_name + '-' + str(node_id + 1)

        # notify on every failed PS we find and set notified state to True
        try:
            for PS in power_states['FAIL']:
                if not self.notified_power_supply_failure[node_id][PS]:
                    message = PS + " in " + node_name + " failed"
                    subject = "[ALERT] Qumulo Power Supply Failure " + node_name
                    self.notify(subject,
                                message,
                                "powerSupplyFailureTrap",
                                [(rfc1902.ObjectName('1.3.6.1.4.1.47017.8'),
                                  rfc1902.OctetString(node_name)),
                                 (rfc1902.ObjectName('1.3.6.1.4.1.47017.11'),
                                  rfc1902.OctetString(PS))
                                 ]
                                )
                    self.notified_power_supply_failure[node_id][PS] = True
        except TypeError, err:
            self.logger.warn("WARNING: IPMI Exception, please verify IPMI config. (%s)"
                     % str(err))
コード例 #2
0
 def dictify(self):
     if self.__varbinds_dict is None:
         self.__varbinds_dict = {}
         for entry in self.__varbinds:
             if isinstance(entry, list):
                 for oid, value in entry:
                     # always store internal data using rfc1902.ObjectNames, which are pyasn1 ObjectIdentifiers, which behave like tuples
                     if not value.isSameTypeWith(rfc1905.noSuchObject):
                         self.__varbinds_dict[rfc1902.ObjectName(
                             oid)] = value
             else:
                 oid, value = entry
                 if not value.isSameTypeWith(rfc1905.noSuchObject):
                     self.__varbinds_dict[rfc1902.ObjectName(oid)] = value
コード例 #3
0
    def __getFDBTable(self, result):
        portsTable = self.snmp.walk(OID.dot1dTpFdbPort)
        learnedTypeTable = self.snmp.walk(OID.dot1dTpFdbStatus)

        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.getSwitchName()))

        #return result
        return
        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)
コード例 #4
0
ファイル: snmpclient.py プロジェクト: rpuligandla/csr
    def getColumn(self, name, context=None):

        # if val is not None and varBindHead[idx].isPrefixOf(name): in cmdgen
        # fails so I can't use the oneliner method
        oid = ''
        if self.isDotNotation(name):
            oid = name
        else:
            oid = self.mibs[name].get('oid')

        if context == None:
            context = self.context

        cmdGen = MyCmdGen()
        errorIndication, errorStatus, _, varBinds = cmdGen.getColumn(
            self.agent, context, self.host, self.port, rfc1902.ObjectName(oid))
        if errorIndication:
            raise IOError(errorIndication)
        if errorStatus:
            if len(varBinds) > 0 and errorStatus == 32:
                pass
            else:
                raise SNMPError('getcolumn on ' + oid + '(' + name + ')',
                                errorStatus)

        #if errorStatus:
        # Throw an error??

        # do we need to do error checking on this???
        # what format should this return in???
        formattedList = []
        for val in varBinds:
            formattedList.append(val[0][1].prettyPrint())

        return formattedList
コード例 #5
0
ファイル: switch.py プロジェクト: sohonet/HEN
    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)
コード例 #6
0
ファイル: snmpclient.py プロジェクト: rpuligandla/csr
    def get(self, name, instance=0, context=None):
        oid = ''

        if self.isDotNotation(name):
            oid = name
        else:
            oid = self.mibs[name].get('oid')
        # 2012-04-04, pcankar: if instance is -1 leave oid unchanged
        if instance != -1:
            oid += '.' + str(instance)

        if context == None:
            context = self.context

        cmdGen = MyCmdGen()
        errorIndication, errorStatus, _, varBinds = cmdGen.getCmd(
            self.agent, context, self.host, self.port, rfc1902.ObjectName(oid))

        if errorIndication:
            raise IOError(errorIndication)
        if errorStatus:
            raise SNMPError('get on ' + oid + '(' + name + ')', errorStatus)
            # Throw an error??
        # do we need to do error checking on this???
        #print "Getting %s (%s) = %s" % (name, oid, str(varBinds[-1][1].prettyPrint()))

        return varBinds[-1][1].prettyPrint()
コード例 #7
0
ファイル: snmpclient.py プロジェクト: rpuligandla/csr
    def getnext(self, name, instance=0, context=None):

        # if val is not None and varBindHead[idx].isPrefixOf(name): in cmdgen
        # fails so I can't use the oneliner method

        oid = ''
        if self.isDotNotation(name):
            oid = name
        else:
            oid = self.mibs[name].get('oid')
        # 2012-04-04, pcankar: if instance is -1 leave oid unchanged
        if instance != -1:
            oid += '.' + str(instance)

        if context == None:
            context = self.context

        cmdGen = MyCmdGen()
        errorIndication, errorStatus, _, varBinds = cmdGen.nextCmd(
            self.agent, context, self.host, self.port, rfc1902.ObjectName(oid))

        if errorIndication:
            raise IOError(errorIndication)
        if errorStatus:
            raise SNMPError('getnext on ' + oid + '(' + name + ')',
                            errorStatus)
        #if errorStatus:
        # Throw an error??

        # do we need to do error checking on this???
        # what format should this return in???
        return varBinds
コード例 #8
0
 def add_oid(self, oid, oid_type_str, getValue):
     oid_num = rfc1902.ObjectName(oid).asTuple()
     oid_type = TYPE_MAP[oid_type_str]
     self.mibBuilder.exportSymbols(
         '__MY_MIB', self.MibScalar(oid_num[:-1], oid_type),
         createVariable(self.MibScalarInstance, getValue, oid_num[:-1],
                        (oid_num[-1], ), oid_type))
コード例 #9
0
ファイル: linksys.py プロジェクト: sohonet/HEN
    def __getSimpleMACTable(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.getDot1qTpFdbPort(True)
        learnedTypeTable = self.getDot1qTpFdbStatus(True)
        result = []

        for learnedTypeTableRow in learnedTypeTable:
            for learnedname, learnedval in learnedTypeTableRow:
                if learnedval == rfc1902.Integer32('3'):
                    learnedname = rfc1902.ObjectName(
                        (learnedname.prettyPrint()).replace(
                            OID.dot1qTpFdbStatus.prettyPrint(),
                            OID.dot1qTpFdbPort.prettyPrint()))
                    for portTableRow in portsTable:
                        for portname, portval in portTableRow:
                            if learnedname == portname:
                                mac = ("%02x:%02x:%02x:%02x:%02x:%02x" % (
                                    int(learnedname[14]), int(learnedname[15]),
                                    int(learnedname[16]), int(learnedname[17]),
                                    int(learnedname[18]), int(
                                        learnedname[19])))
                                mac = mac.replace("0x", "").upper()
                                result.append((mac, str(portval)))
        return result
コード例 #10
0
ファイル: linksys.py プロジェクト: sohonet/HEN
    def addMacsToPorts(self):
        portsTable = self.getDot1qTpFdbPort(True)
        learnedTypeTable = self.getDot1qTpFdbStatus(True)

        self.resetPortsMacInfo()
        for learnedTypeTableRow in learnedTypeTable:
            for learnedname, learnedval in learnedTypeTableRow:
                if learnedval == rfc1902.Integer32('3'):
                    learnedname = rfc1902.ObjectName(
                        (learnedname.prettyPrint()).replace(
                            OID.dot1qTpFdbStatus.prettyPrint(),
                            OID.dot1qTpFdbPort.prettyPrint()))
                    for portTableRow in portsTable:
                        for portname, portval in portTableRow:
                            if learnedname == portname:
                                mac = ("%02x:%02x:%02x:%02x:%02x:%02x" % (
                                    int(learnedname[14]), int(learnedname[15]),
                                    int(learnedname[16]), int(learnedname[17]),
                                    int(learnedname[18]), int(
                                        learnedname[19])))
                                mac = mac.replace("0x", "").upper()
                                port = self.getPort(portval)
                                mac_list = port.getMacs()
                                mac_list.append(mac)
                                port.setMacs(mac_list)
コード例 #11
0
ファイル: subprocess.py プロジェクト: Kryndex/snmpsim
def variate(oid, tag, value, **context):
    # in --v2c-arch some of the items are not defined
    transportDomain = transportAddress = securityModel = securityName = \
        securityLevel = contextName = '<undefined>'
    if 'transportDomain' in context:
        transportDomain = rfc1902.ObjectName(
            context['transportDomain']).prettyPrint()
    if 'transportAddress' in context:
        transportAddress = ':'.join(
            [str(x) for x in context['transportAddress']])
    if 'securityModel' in context:
        securityModel = str(context['securityModel'])
    if 'securityName' in context:
        securityName = str(context['securityName'])
    if 'securityLevel' in context:
        securityLevel = str(context['securityLevel'])
    if 'contextName' in context:
        contextName = str(context['contextName'])

    args = [(x.replace('@TRANSPORTDOMAIN@', transportDomain).replace(
        '@TRANSPORTADDRESS@', transportAddress).replace(
            '@SECURITYMODEL@',
            securityModel).replace('@SECURITYNAME@', securityName).replace(
                '@SECURITYLEVEL@',
                securityLevel).replace('@CONTEXTNAME@', contextName).replace(
                    '@DATAFILE@',
                    context['dataFile']).replace('@OID@', str(oid)).replace(
                        '@TAG@', tag).replace('@ORIGOID@',
                                              str(context['origOid'])).
             replace('@ORIGTAG@',
                     str(sum(
                         [x
                          for x in context['origValue'].tagSet[0]]))).replace(
                              '@ORIGVALUE@',
                              str(context['origValue'])).replace(
                                  '@SETFLAG@',
                                  str(int(context['setFlag']))).replace(
                                      '@NEXTFLAG@',
                                      str(int(context['nextFlag']))).replace(
                                          '@SUBTREEFLAG@',
                                          str(int(context['subtreeFlag']))))
            for x in split(value, ' ')]

    log.msg('subprocess: executing external process "%s"' % ' '.join(args))

    call = (hasattr(subprocess, 'check_output') and subprocess.check_output
            or hasattr(subprocess, 'check_call') and subprocess.check_call
            or subprocess.call)
    if not hasattr(subprocess, 'check_output'):
        log.msg('subprocess: old Python, expect no output!')

    try:
        return oid, tag, call(args, shell=moduleContext['settings']['shell'])
    except (hasattr(subprocess, 'CalledProcessError')
            and subprocess.CalledProcessError or Exception):
        log.msg('subprocess: external program execution failed')
        return context['origOid'], tag, context['errorStatus']
コード例 #12
0
def nodename(oid):
    """Translate dotted-decimal oid or oid tuple to symbolic name"""
    if isinstance(oid, str):
        oid = rfc1902.ObjectName(oid)
    oid = __mibViewController.getNodeLocation(oid)  # pylint:disable=R0204
    name = '::'.join(oid[:-1])
    noid = '.'.join([str(x) for x in oid[-1]])
    if noid:
        name += '.' + noid
    return name
コード例 #13
0
 def test__get_device_nibble_map(self):
     self.client = snmp_client.get_client(self.snmp_info)
     seg_id = 1001
     egrs_oid = hp_const.OID_VLAN_EGRESS_PORT + '.' + str(seg_id)
     varbinds = [(rfc1902.ObjectName('1.3.6.1.2.1.17.7.1.4.3.1.2.1001'),
                  rfc1902.OctetString('\x80'))]
     with contextlib.nested(
             mock.patch.object(snmp_client.SNMPClient,
                               'get',
                               return_value=varbinds)):
         egbytes = self.driver._get_device_nibble_map(self.client, egrs_oid)
     self.assertEqual(egbytes, '\x80')
コード例 #14
0
ファイル: snmpclient.py プロジェクト: rpuligandla/csr
    def getBulk(self,
                name,
                nonRepeaters,
                maxRepititions,
                context=None,
                dict=False):

        # if val is not None and varBindHead[idx].isPrefixOf(name): in cmdgen
        # fails so I can't use the oneliner method
        oid = ''
        if self.isDotNotation(name):
            oid = name
        else:
            oid = self.mibs[name].get('oid')

        if context == None:
            context = self.context


#        cmdGen = MyCmdGen()
#        errorIndication, errorStatus, _, varBinds = cmdGen.getBulk(
#        self.agent, context,
#        self.host, self.port,
#        nonRepeaters,
#        maxRepititions,
#        rfc1902.ObjectName(oid))

        errorIndication, errorStatus, _, varBinds = cg.CommandGenerator(
        ).bulkCmd(cg.CommunityData(self.agent, context),
                  cg.UdpTransportTarget((self.host, self.port)), nonRepeaters,
                  maxRepititions, rfc1902.ObjectName(oid))

        if errorIndication:
            raise IOError(errorIndication)
        if errorStatus:
            if len(varBinds) > 0 and errorStatus == 32:
                pass
            else:
                raise SNMPError('getbulk on ' + oid + '(' + name + ')',
                                errorStatus)

        formattedList = []
        for val in varBinds:
            formattedList.append(val[0][1].prettyPrint())
        formattedDict = {}
        for val in varBinds:
            formattedDict[val[0][0].prettyPrint()] = val[0][1].prettyPrint()
        if dict:
            return formattedDict
        return formattedList
コード例 #15
0
    def send(self, mib, value, value_type='OctetString'):
        """
        v1 snmp, public
        """
        if not self.authData:
            raise ValueError('Credentials not set, use .security_XXX() methods')
        obj_class = getattr(rfc1902, value_type)
        errorIndication = self.ntfOrg.sendNotification(self.authData,
                                                       ntforg.UdpTransportTarget((self.host, self.port)), #transportTarget
                                                       'trap', #notifyType
                                                       ntforg.MibVariable('SNMPv2-MIB', 'snmpOutTraps'), #notificationType
                                                       ((rfc1902.ObjectName(mib),
                                                         obj_class(value))))

        if errorIndication:
            raise RuntimeError('Notification not sent: %s' % errorIndication)
        print('Sent SNMP TRAP {} "{}" to {} {}'.format(mib, value, self.host, self.port))
コード例 #16
0
 def _to_pysnmp(self, value):
     """ Convert connection plugin object into pysnmp objects """
     if value is None:
         return None
     if isinstance(value, OctetString):
         return rfc1902.OctetString(str(value.value))
     if isinstance(value, ObjectIdentifier):
         return rfc1902.ObjectName(str(value.value))
     if isinstance(value, Integer32):
         return rfc1902.Integer32(int(value.value))
     if isinstance(value, Counter32):
         return rfc1902.Counter32(long(value.value))
     if isinstance(value, IpAddress):
         return rfc1902.IpAddress(str(value.value))
     if isinstance(value, Gauge32):
         return rfc1902.Gauge32(long(value.value))
     if isinstance(value, TimeTicks):
         return rfc1902.TimeTicks(long(value.value))
     if isinstance(value, Opaque):
         return rfc1902.Opaque(value.value)  # FIXME
     if isinstance(value, Counter64):
         return rfc1902.Counter64(str(value.value))
     raise SnmpError('Invalid type: %s' % value.__class__.__name__)
コード例 #17
0
 def get_by_dict(self, oid):
     self.dictify()
     if oid is None and len(list(self.__varbinds_dict.keys())) == 1:
         oid = list(self.__varbinds_dict.keys())[0]
     elif oid is None:
         raise RuntimeError(
             "Cannot query oid %r if multiple varBinds keys are present")
     if isinstance(oid, str):
         if oid in self.__varbinds_dict:
             value = self.__varbinds_dict[oid]
         else:
             value = self.__varbinds_dict[rfc1902.ObjectName(nodeid(oid))]
         if value.isSameTypeWith(rfc1905.noSuchObject):
             return None
         return value
     elif isinstance(oid, tuple) or isinstance(oid, rfc1902.ObjectName):
         value = self.__varbinds_dict[oid]
         if value.isSameTypeWith(rfc1905.noSuchObject):
             return None
         else:
             return value
     else:
         raise RuntimeError("Unknown format of oid %r with type %s" %
                            (oid, oid.__class__.__name__))
コード例 #18
0
 def rpc_get(self, id, *object_ids):
     pysnmp_var_names = []
     for object_id in object_ids:
         pysnmp_var_names.append(rfc1902.ObjectName(str(object_id)))
     self._conn.get(pysnmp_var_names, (self._on_rpc_get, id))
コード例 #19
0
class VarBind(univ.Sequence):
    componentType = namedtype.NamedTypes(
        namedtype.NamedType('name', rfc1902.ObjectName()),
        namedtype.NamedType('', _BindValue()))
コード例 #20
0
ファイル: mibvar.py プロジェクト: InviNets/ReadingsToSNMP
    def resolveWithMib(self, mibViewController, oidOnly=False):
        if self.__mibSourcesToAdd is not None:
            mibSources = tuple(
                [ ZipMibSource(x) for x in self.__mibSourcesToAdd ]
            ) + mibViewController.mibBuilder.getMibSources()
            mibViewController.mibBuilder.setMibSources(*mibSources)
            self.__mibSourcesToAdd = None

        if self.__modNamesToLoad is not None:
            mibViewController.mibBuilder.loadModules(*self.__modNamesToLoad)
            self.__modNamesToLoad = None

        if self.__state & (self.stOidOnly | self.stClean):
            return self

        MibScalar, MibTableColumn, = mibViewController.mibBuilder.importSymbols('SNMPv2-SMI', 'MibScalar', 'MibTableColumn')

        if len(self.__args) == 1:  # OID or label
            try:
                self.__oid = rfc1902.ObjectName(self.__args[0])
            except PyAsn1Error:
                try:
                    label = tuple(self.__args[0].split('.'))
                except ValueError:
                    raise PySnmpError('Bad OID format %s' % (self.__args[0],))
                prefix, label, suffix = mibViewController.getNodeNameByOid(
                    label
                )
             
                if suffix:
                    try:
                        suffix = tuple([ int(x) for x in suffix ])
                    except ValueError:
                        raise PySnmpError('Unknown object name component %s' % (suffix,))

                self.__oid = rfc1902.ObjectName(prefix + suffix)

                self.__state |= self.stOidOnly

                if oidOnly:
                    return self
            else:
                self.__state |= self.stOidOnly

                if oidOnly:
                    return self

                prefix, label, suffix = mibViewController.getNodeNameByOid(
                    self.__oid
                )

            modName, symName, _ = mibViewController.getNodeLocation(prefix)

            self.__modName = modName
            self.__symName = symName

            self.__label = label

            mibNode, = mibViewController.mibBuilder.importSymbols(
                modName, symName
            )

            self.__mibNode = mibNode

            if isinstance(mibNode, MibTableColumn): # table column
                rowModName, rowSymName, _ = mibViewController.getNodeLocation(
                    mibNode.name[:-1]
                )
                rowNode, = mibViewController.mibBuilder.importSymbols(
                    rowModName, rowSymName
                )
                self.__indices = rowNode.getIndicesFromInstId(suffix)
            elif isinstance(mibNode, MibScalar): # scalar
                self.__indices = ( rfc1902.ObjectName(suffix), )
            else:
                self.__indices = ( rfc1902.ObjectName(suffix), )
                self.__state |= self.stUnresolved
            self.__state |= self.stClean
            return self
        elif len(self.__args) > 1:  # MIB, symbol[, index, index ...]
            self.__modName = self.__args[0]
            if self.__args[1]:
                self.__symName = self.__args[1]
            else:
                mibViewController.mibBuilder.loadModules(self.__modName)
                oid, _, _ = mibViewController.getFirstNodeName(self.__modName)
                _, self.__symName, _ = mibViewController.getNodeLocation(oid)

            mibNode, = mibViewController.mibBuilder.importSymbols(
                self.__modName, self.__symName
            )

            self.__mibNode = mibNode

            self.__indices = ()
            self.__oid = rfc1902.ObjectName(mibNode.getName())

            prefix, label, suffix = mibViewController.getNodeNameByOid(
                self.__oid
            )
            self.__label = label

            if isinstance(mibNode, MibTableColumn): # table
                rowModName, rowSymName, _ = mibViewController.getNodeLocation(
                    mibNode.name[:-1]
                )
                rowNode, = mibViewController.mibBuilder.importSymbols(
                    rowModName, rowSymName
                )
                if self.__args[2:]:
                    instIds = rowNode.getInstIdFromIndices(*self.__args[2:])
                    self.__oid += instIds
                    self.__indices = rowNode.getIndicesFromInstId(instIds)
            elif self.__args[2:]: # any other kind of MIB node with indices
                instId = rfc1902.ObjectName(
                    '.'.join([ str(x) for x in self.__args[2:] ])
                )
                self.__oid += instId
                self.__indices = ( instId, )
            self.__state |= (self.stClean | self.stOidOnly)
            return self
        else:
            raise PySnmpError('Non-OID, label or MIB symbol')
コード例 #21
0
ファイル: ntforg.py プロジェクト: ithek/pysnmp
#     include managed object information 1.3.6.1.2.1.1.1.0 = 'my system'
#     include managed object information 1.3.6.1.2.1.1.3.0 = 567
errorIndication = ntfOrg.sendNotification(
    ntforg.UsmUserData('usr-sha-aes',
                       'authkey1',
                       'privkey1',
                       authProtocol=ntforg.usmHMACSHAAuthProtocol,
                       privProtocol=ntforg.usmAesCfb128Protocol),
    ntforg.Udp6TransportTarget(('::1', 162)), 'trap',
    ntforg.MibVariable('SNMPv2-MIB', 'authenticationFailure'),
    ('1.3.6.1.2.1.1.1.0', rfc1902.OctetString('my system')),
    ('1.3.6.1.2.1.1.3.0', rfc1902.TimeTicks(567)))

if errorIndication:
    print('Notification not sent: %s' % errorIndication)

# Using
#     SNMPv3 user 'usr-none-none', no auth, no priv
#     over IPv4/UDP
#     send TRAP notification
#     with TRAP ID 'authenticationFailure' specified as a MIB symbol
#     include managed object information 1.3.6.1.2.1.1.2.0 = 1.3.6.1.2.1.1.1
errorIndication = ntfOrg.sendNotification(
    ntforg.UsmUserData('usr-none-none'),
    ntforg.UdpTransportTarget(('localhost', 162)), 'trap',
    ntforg.MibVariable('SNMPv2-MIB', 'authenticationFailure'),
    ('1.3.6.1.2.1.1.2.0', rfc1902.ObjectName('1.3.6.1.2.1.1.1')))

if errorIndication:
    print('Notification not sent: %s' % errorIndication)
コード例 #22
0
ファイル: multiplex.py プロジェクト: Kryndex/snmpsim
def variate(oid, tag, value, **context):
    if 'settings' not in recordContext:
        recordContext['settings'] = dict(
            [split(x, '=') for x in split(value, ',')])
        if 'dir' not in recordContext['settings']:
            log.msg('multiplex: snapshot directory not specified')
            return context['origOid'], tag, context['errorStatus']

        recordContext['settings']['dir'] = recordContext['settings'][
            'dir'].replace('/', os.path.sep)
        if recordContext['settings']['dir'][0] != os.path.sep:
            for x in confdir.data:
                d = os.path.join(x, recordContext['settings']['dir'])
                if os.path.exists(d):
                    break
            else:
                log.msg('multiplex: directory %s not found' %
                        recordContext['settings']['dir'])
                return context['origOid'], tag, context['errorStatus']
        else:
            d = recordContext['settings']['dir']
        recordContext['dirmap'] = dict([
            (int(os.path.basename(x).split(os.path.extsep)[0]),
             os.path.join(d, x)) for x in os.listdir(d) if x[-7:] == 'snmprec'
        ])
        recordContext['keys'] = list(recordContext['dirmap'].keys())
        recordContext['bounds'] = (min(recordContext['keys']),
                                   max(recordContext['keys']))
        if 'period' in recordContext['settings']:
            recordContext['settings']['period'] = float(
                recordContext['settings']['period'])
        else:
            recordContext['settings']['period'] = 60.0
        if 'wrap' in recordContext['settings']:
            recordContext['settings']['wrap'] = bool(
                recordContext['settings']['wrap'])
        else:
            recordContext['settings']['wrap'] = False
        if 'control' in recordContext['settings']:
            recordContext['settings']['control'] = rfc1902.ObjectName(
                recordContext['settings']['control'])
            log.msg(
                'multiplex: using control OID %s for subtree %s, time-based multiplexing disabled'
                % (recordContext['settings']['control'], oid))

        recordContext['ready'] = True

    if 'ready' not in recordContext:
        return context['origOid'], tag, context['errorStatus']

    if oid not in moduleContext:
        moduleContext[oid] = {}

    if context['setFlag']:
        if 'control' in recordContext['settings'] and \
                        recordContext['settings']['control'] == context['origOid']:
            fileno = int(context['origValue'])
            if fileno >= len(recordContext['keys']):
                log.msg('multiplex: .snmprec file number %s over limit of %s' %
                        (fileno, len(recordContext['keys'])))
                return context['origOid'], tag, context['errorStatus']
            moduleContext[oid]['fileno'] = fileno
            log.msg('multiplex: switched to file #%s (%s)' %
                    (recordContext['keys'][fileno],
                     recordContext['dirmap'][recordContext['keys'][fileno]]))
            return context['origOid'], tag, context['origValue']
        else:
            return context['origOid'], tag, context['errorStatus']

    if 'control' in recordContext['settings']:
        if 'fileno' not in moduleContext[oid]:
            moduleContext[oid]['fileno'] = 0
        if (not context['nextFlag'] and recordContext['settings']['control']
                == context['origOid']):
            return context['origOid'], tag, rfc1902.Integer32(
                moduleContext[oid]['fileno'])
    else:
        timeslot = (time.time() - moduleContext['booted']) % (
            recordContext['settings']['period'] * len(recordContext['dirmap']))
        fileslot = int(
            timeslot /
            recordContext['settings']['period']) + recordContext['bounds'][0]

        fileno = bisect.bisect(recordContext['keys'], fileslot) - 1

        if ('fileno' not in moduleContext[oid]
                or moduleContext[oid]['fileno'] < fileno
                or recordContext['settings']['wrap']):
            moduleContext[oid]['fileno'] = fileno

    datafile = recordContext['dirmap'][recordContext['keys'][moduleContext[oid]
                                                             ['fileno']]]

    if ('datafile' not in moduleContext[oid]
            or moduleContext[oid]['datafile'] != datafile):
        if 'datafileobj' in moduleContext[oid]:
            moduleContext[oid]['datafileobj'].close()
        moduleContext[oid]['datafileobj'] = RecordIndex(
            datafile, SnmprecRecord()).create()
        moduleContext[oid]['datafile'] = datafile

        log.msg('multiplex: switching to data file %s for %s' %
                (datafile, context['origOid']))

    text, db = moduleContext[oid]['datafileobj'].getHandles()

    textOid = str(
        rfc1902.OctetString('.'.join(['%s' % x for x in context['origOid']])))

    try:
        line = moduleContext[oid]['datafileobj'].lookup(textOid)
    except KeyError:
        offset = searchRecordByOid(context['origOid'], text, SnmprecRecord())
        exactMatch = False
    else:
        offset, subtreeFlag, prevOffset = line.split(str2octs(','))
        exactMatch = True

    text.seek(int(offset))

    line, _, _ = getRecord(text)  # matched line

    if context['nextFlag']:
        if exactMatch:
            line, _, _ = getRecord(text)
    else:
        if not exactMatch:
            return context['origOid'], tag, context['errorStatus']

    if not line:
        return context['origOid'], tag, context['errorStatus']

    try:
        oid, value = SnmprecRecord().evaluate(line)
    except error.SnmpsimError:
        oid, value = context['origOid'], context['errorStatus']

    return oid, tag, value
コード例 #23
0
def nodeinfo(oid):
    """Translate dotted-decimal oid to a tuple with symbolic info"""
    if isinstance(oid, str):
        oid = rfc1902.ObjectName(oid)
    return __mibViewController.getNodeLocation(
        oid), __mibViewController.getNodeName(oid)
コード例 #24
0
 def rpc_set(self, id, var_binds):
     pysnmp_var_binds = []
     for object_id, value in var_binds.items():
         pysnmp_var_binds.append(
             (rfc1902.ObjectName(str(object_id)), self._to_pysnmp(value)))
     self._conn.set(pysnmp_var_binds, (self._on_rpc_set, id))
コード例 #25
0
#     to an Agent at 195.218.195.228:161
#     for an OID in string form
#     stop whenever received OID goes out of initial prefix (it may be a table)
#
# This script performs similar to the following Net-SNMP command:
#
# $ snmpwalk -v3 -l noAuthNoPriv -u usr-none-none -ObentU 195.218.195.228:161  1.3.6.1.2.1.1
#
from twisted.internet import reactor, defer
from pysnmp.entity import engine, config
from pysnmp.entity.rfc3413.twisted import cmdgen
from pysnmp.proto import rfc1902, rfc1905
from pysnmp.carrier.twisted.dgram import udp

# Initial OID prefix
initialOID = rfc1902.ObjectName('1.3.6.1.2.1.1')

# Create SNMP engine instance
snmpEngine = engine.SnmpEngine()

#
# SNMPv3/USM setup
#

# user: usr-none-none, no auth, no priv
config.addV3User(
    snmpEngine,
    'usr-none-none',
)
config.addTargetParams(snmpEngine, 'my-creds', 'usr-none-none', 'noAuthNoPriv')
コード例 #26
0
 def _do_rpc_walk(self, id, request_object_id, object_id, res):
     pysnmp_var_names = [rfc1902.ObjectName(object_id)]
     self._conn.get_bulk(pysnmp_var_names,
                         (self._on_rpc_walk, (id, request_object_id, res)))
コード例 #27
0
ファイル: rfc1902.py プロジェクト: zxl359592450/pysnmp
    def resolveWithMib(self, mibViewController):
        """Perform MIB variable ID conversion.

        Parameters
        ----------
        mibViewController : :py:class:`~pysnmp.smi.view.MibViewController`
            class instance representing MIB browsing functionality.

        Returns
        -------
        : :py:class:`~pysnmp.smi.rfc1902.ObjectIdentity`
            reference to itself

        Raises
        ------
        SmiError
           In case of fatal MIB hanling errora

        Notes
        -----
        Calling this method might cause the following sequence of
        events (exact details depends on many factors):

        * ASN.1 MIB file downloaded and handed over to
          :py:class:`~pysmi.compiler.MibCompiler` for conversion into
          Python MIB module (based on pysnmp classes)
        * Python MIB module is imported by SNMP engine, internal indices
          created
        * :py:class:`~pysnmp.smi.view.MibViewController` looks up the
          rest of MIB identification information based on whatever information
          is already available, :py:class:`~pysnmp.smi.rfc1902.ObjectIdentity`
          class instance
          gets updated and ready for further use.

        Examples
        --------
        >>> objectIdentity = ObjectIdentity('SNMPv2-MIB', 'sysDescr')
        >>> objectIdentity.resolveWithMib(mibViewController)
        ObjectIdentity('SNMPv2-MIB', 'sysDescr')
        >>>

        """
        if self.__mibSourcesToAdd is not None:
            debug.logger & debug.flagMIB and debug.logger('adding MIB sources %s' % ', '.join(self.__mibSourcesToAdd))
            mibViewController.mibBuilder.addMibSources(
                *[ZipMibSource(x) for x in self.__mibSourcesToAdd]
            )
            self.__mibSourcesToAdd = None

        if self.__asn1SourcesToAdd is None:
            addMibCompiler(mibViewController.mibBuilder,
                           ifAvailable=True, ifNotAdded=True)
        else:
            debug.logger & debug.flagMIB and debug.logger(
                'adding MIB compiler with source paths %s' % ', '.join(self.__asn1SourcesToAdd))
            addMibCompiler(
                mibViewController.mibBuilder,
                sources=self.__asn1SourcesToAdd,
                searchers=self.__asn1SourcesOptions.get('searchers'),
                borrowers=self.__asn1SourcesOptions.get('borrowers'),
                destination=self.__asn1SourcesOptions.get('destination'),
                ifAvailable=self.__asn1SourcesOptions.get('ifAvailable'),
                ifNotAdded=self.__asn1SourcesOptions.get('ifNotAdded')
            )
            self.__asn1SourcesToAdd = self.__asn1SourcesOptions = None

        if self.__modNamesToLoad is not None:
            debug.logger & debug.flagMIB and debug.logger('loading MIB modules %s' % ', '.join(self.__modNamesToLoad))
            mibViewController.mibBuilder.loadModules(*self.__modNamesToLoad)
            self.__modNamesToLoad = None

        if self.__state & self.stClean:
            return self

        MibScalar, MibTableColumn = mibViewController.mibBuilder.importSymbols('SNMPv2-SMI', 'MibScalar',
                                                                               'MibTableColumn')

        self.__indices = ()

        if isinstance(self.__args[0], ObjectIdentity):
            self.__args[0].resolveWithMib(mibViewController)

        if len(self.__args) == 1:  # OID or label or MIB module
            debug.logger & debug.flagMIB and debug.logger('resolving %s as OID or label' % self.__args)
            try:
                # pyasn1 ObjectIdentifier or sequence of ints or string OID
                self.__oid = rfc1902.ObjectName(self.__args[0])  # OID
            except PyAsn1Error:
                # sequence of sub-OIDs and labels
                if isinstance(self.__args[0], (list, tuple)):
                    prefix, label, suffix = mibViewController.getNodeName(
                        self.__args[0]
                    )
                # string label
                elif '.' in self.__args[0]:
                    prefix, label, suffix = mibViewController.getNodeNameByOid(
                        tuple(self.__args[0].split('.'))
                    )
                # MIB module name
                else:
                    modName = self.__args[0]
                    mibViewController.mibBuilder.loadModules(modName)
                    if self.__kwargs.get('last'):
                        prefix, label, suffix = mibViewController.getLastNodeName(modName)
                    else:
                        prefix, label, suffix = mibViewController.getFirstNodeName(modName)

                if suffix:
                    try:
                        suffix = tuple([int(x) for x in suffix])
                    except ValueError:
                        raise SmiError('Unknown object name component %r' % (suffix,))
                self.__oid = rfc1902.ObjectName(prefix + suffix)
            else:
                prefix, label, suffix = mibViewController.getNodeNameByOid(
                    self.__oid
                )

            debug.logger & debug.flagMIB and debug.logger(
                'resolved %r into prefix %r and suffix %r' % (self.__args, prefix, suffix))

            modName, symName, _ = mibViewController.getNodeLocation(prefix)

            self.__modName = modName
            self.__symName = symName

            self.__label = label

            mibNode, = mibViewController.mibBuilder.importSymbols(
                modName, symName
            )

            self.__mibNode = mibNode

            debug.logger & debug.flagMIB and debug.logger('resolved prefix %r into MIB node %r' % (prefix, mibNode))

            if isinstance(mibNode, MibTableColumn):  # table column
                if suffix:
                    rowModName, rowSymName, _ = mibViewController.getNodeLocation(
                        mibNode.name[:-1]
                    )
                    rowNode, = mibViewController.mibBuilder.importSymbols(
                        rowModName, rowSymName
                    )
                    self.__indices = rowNode.getIndicesFromInstId(suffix)
            elif isinstance(mibNode, MibScalar):  # scalar
                if suffix:
                    self.__indices = (rfc1902.ObjectName(suffix),)
            else:
                if suffix:
                    self.__indices = (rfc1902.ObjectName(suffix),)
            self.__state |= self.stClean

            debug.logger & debug.flagMIB and debug.logger('resolved indices are %r' % (self.__indices,))

            return self
        elif len(self.__args) > 1:  # MIB, symbol[, index, index ...]
            # MIB, symbol, index, index
            if self.__args[0] and self.__args[1]:
                self.__modName = self.__args[0]
                self.__symName = self.__args[1]
            # MIB, ''
            elif self.__args[0]:
                mibViewController.mibBuilder.loadModules(self.__args[0])
                if self.__kwargs.get('last'):
                    prefix, label, suffix = mibViewController.getLastNodeName(self.__args[0])
                else:
                    prefix, label, suffix = mibViewController.getFirstNodeName(self.__args[0])
                self.__modName, self.__symName, _ = mibViewController.getNodeLocation(prefix)
            # '', symbol, index, index
            else:
                prefix, label, suffix = mibViewController.getNodeName(self.__args[1:])
                self.__modName, self.__symName, _ = mibViewController.getNodeLocation(prefix)

            mibNode, = mibViewController.mibBuilder.importSymbols(
                self.__modName, self.__symName
            )

            self.__mibNode = mibNode

            self.__oid = rfc1902.ObjectName(mibNode.getName())

            prefix, label, suffix = mibViewController.getNodeNameByOid(
                self.__oid
            )
            self.__label = label

            debug.logger & debug.flagMIB and debug.logger(
                'resolved %r into prefix %r and suffix %r' % (self.__args, prefix, suffix))

            if isinstance(mibNode, MibTableColumn):  # table
                rowModName, rowSymName, _ = mibViewController.getNodeLocation(
                    mibNode.name[:-1]
                )
                rowNode, = mibViewController.mibBuilder.importSymbols(
                    rowModName, rowSymName
                )
                if self.__args[2:]:
                    try:
                        instIds = rowNode.getInstIdFromIndices(*self.__args[2:])
                        self.__oid += instIds
                        self.__indices = rowNode.getIndicesFromInstId(instIds)
                    except PyAsn1Error:
                        raise SmiError('Instance index %r to OID convertion failure at object %r: %s' % (
                            self.__args[2:], mibNode.getLabel(), sys.exc_info()[1]))
            elif self.__args[2:]:  # any other kind of MIB node with indices
                if self.__args[2:]:
                    instId = rfc1902.ObjectName(
                        '.'.join([str(x) for x in self.__args[2:]])
                    )
                    self.__oid += instId
                    self.__indices = (instId,)
            self.__state |= self.stClean

            debug.logger & debug.flagMIB and debug.logger('resolved indices are %r' % (self.__indices,))

            return self
        else:
            raise SmiError('Non-OID, label or MIB symbol')
コード例 #28
0
# Error/response reciever
def receiveResponse(cbCtx):
    (errorIndication, errorStatus, errorIndex, varBinds) = cbCtx
    if errorIndication:
        print('Error: %s' % errorIndication)
        reactor.stop()
        return
    if errorStatus:
        print('Error: %s at %s' % (errorStatus.prettyPrint(), errorIndex))
        reactor.stop()
        return
    for oid, val in varBinds:
        if val is None:
            print(oid.prettyPrint())
        else:
            print('%s = %s' % (oid.prettyPrint(), val.prettyPrint()))
    reactor.stop()

df = cmdgen.SetCommandGenerator().sendReq(
     snmpEngine, 
    'my-router',
    ( ((1,3,6,1,2,1,1,1,0), rfc1902.OctetString('Grinch')), 
      ((1,3,6,1,2,1,1,2,0), rfc1902.ObjectName('1.3.6.1.4.1.20408.4')) )
)

df.addCallback(receiveResponse)

# Run I/O dispatcher which would send pending queries and process response
reactor.run()
コード例 #29
0
ファイル: snmpwalk.py プロジェクト: NoppharutCode/TDA
    ast = Parser().parse(
        Scanner().tokenize(' '.join(sys.argv[1:]))
    )

    ctx = {}

    # Apply configuration to SNMP entity
    main.generator((snmpEngine, ctx), ast)
    msgmod.generator((snmpEngine, ctx), ast)
    secmod.generator((snmpEngine, ctx), ast)    
    mibview.generator((snmpEngine, ctx), ast)
    target.generator((snmpEngine, ctx), ast)
    pdu.readPduGenerator((snmpEngine, ctx), ast)
    generator((snmpEngine, ctx), ast)
    
    ctx['myHeadVars'] = [ rfc1902.ObjectName(x[0]) for x in ctx['varBinds'] ]

    cmdgen.NextCommandGenerator().sendVarBinds(
        snmpEngine,
        ctx['addrName'],
        ctx.get('contextEngineId'), ctx.get('contextName', ''),
        ctx['varBinds'],
        cbFun, ctx
    )

    snmpEngine.transportDispatcher.runDispatcher()

except KeyboardInterrupt:
    sys.stderr.write('Shutting down...\n')

except error.PySnmpError:
コード例 #30
0
ファイル: snmpfwd-server.py プロジェクト: beausea/snmpfwd
def main():
    class CommandResponder(cmdrsp.CommandResponderBase):
        pduTypes = (rfc1905.SetRequestPDU.tagSet, rfc1905.GetRequestPDU.tagSet,
                    rfc1905.GetNextRequestPDU.tagSet,
                    rfc1905.GetBulkRequestPDU.tagSet)

        def handleMgmtOperation(self, snmpEngine, stateReference, contextName,
                                pdu, acInfo):
            trunkReq = gCurrentRequestContext.copy()

            trunkReq['snmp-pdu'] = pdu

            pluginIdList = trunkReq['plugins-list']

            logCtx = LogString(trunkReq)

            reqCtx = {}

            for pluginNum, pluginId in enumerate(pluginIdList):

                st, pdu = pluginManager.processCommandRequest(
                    pluginId, snmpEngine, pdu, trunkReq, reqCtx)

                if st == status.BREAK:
                    log.debug('plugin %s inhibits other plugins' % pluginId,
                              ctx=logCtx)
                    pluginIdList = pluginIdList[:pluginNum]
                    break

                elif st == status.DROP:
                    log.debug(
                        'received SNMP message, plugin %s muted request' %
                        pluginId,
                        ctx=logCtx)
                    self.releaseStateInformation(stateReference)
                    return

                elif st == status.RESPOND:
                    log.debug(
                        'received SNMP message, plugin %s forced immediate response'
                        % pluginId,
                        ctx=logCtx)

                    try:
                        self.sendPdu(snmpEngine, stateReference, pdu)

                    except PySnmpError:
                        log.error('failure sending SNMP response', ctx=logCtx)

                    else:
                        self.releaseStateInformation(stateReference)

                    return

            # pass query to trunk

            trunkIdList = trunkReq['trunk-id-list']
            if trunkIdList is None:
                log.error('no route configured', ctx=logCtx)
                self.releaseStateInformation(stateReference)
                return

            for trunkId in trunkIdList:

                cbCtx = pluginIdList, trunkId, trunkReq, snmpEngine, stateReference, reqCtx

                try:
                    msgId = trunkingManager.sendReq(trunkId, trunkReq,
                                                    self.trunkCbFun, cbCtx)

                except SnmpfwdError:
                    log.error(
                        'received SNMP message, message not sent to trunk "%s"'
                        % sys.exc_info()[1],
                        ctx=logCtx)
                    return

                log.debug(
                    'received SNMP message, forwarded as trunk message #%s' %
                    msgId,
                    ctx=logCtx)

        def trunkCbFun(self, msgId, trunkRsp, cbCtx):
            pluginIdList, trunkId, trunkReq, snmpEngine, stateReference, reqCtx = cbCtx

            for key in tuple(trunkRsp):
                if key != 'callflow-id':
                    trunkRsp['client-' + key] = trunkRsp[key]
                    del trunkRsp[key]

            trunkRsp['callflow-id'] = trunkReq['callflow-id']

            logCtx = LogString(trunkRsp)

            if trunkRsp['client-error-indication']:
                log.info(
                    'received trunk message #%s, remote end reported error-indication "%s", NOT responding'
                    % (msgId, trunkRsp['client-error-indication']),
                    ctx=logCtx)

            elif 'client-snmp-pdu' not in trunkRsp:
                log.info(
                    'received trunk message #%s, remote end does not send SNMP PDU, NOT responding'
                    % msgId,
                    ctx=logCtx)

            else:
                pdu = trunkRsp['client-snmp-pdu']

                for pluginId in pluginIdList:
                    st, pdu = pluginManager.processCommandResponse(
                        pluginId, snmpEngine, pdu, trunkReq, reqCtx)

                    if st == status.BREAK:
                        log.debug('plugin %s inhibits other plugins' %
                                  pluginId,
                                  ctx=logCtx)
                        break
                    elif st == status.DROP:
                        log.debug('plugin %s muted response' % pluginId,
                                  ctx=logCtx)
                        self.releaseStateInformation(stateReference)
                        return

                try:
                    self.sendPdu(snmpEngine, stateReference, pdu)

                except PySnmpError:
                    log.error('failure sending SNMP response', ctx=logCtx)

                else:
                    log.debug(
                        'received trunk message #%s, forwarded as SNMP message'
                        % msgId,
                        ctx=logCtx)

            self.releaseStateInformation(stateReference)

    #
    # SNMPv3 NotificationReceiver implementation
    #

    class NotificationReceiver(ntfrcv.NotificationReceiver):
        pduTypes = (rfc1157.TrapPDU.tagSet, rfc1905.SNMPv2TrapPDU.tagSet)

        def processPdu(self, snmpEngine, messageProcessingModel, securityModel,
                       securityName, securityLevel, contextEngineId,
                       contextName, pduVersion, pdu, maxSizeResponseScopedPDU,
                       stateReference):

            trunkReq = gCurrentRequestContext.copy()

            if messageProcessingModel == 0:
                pdu = rfc2576.v1ToV2(pdu)

                # TODO: why this is not automatic?
                v2c.apiTrapPDU.setDefaults(pdu)

            trunkReq['snmp-pdu'] = pdu

            pluginIdList = trunkReq['plugins-list']

            logCtx = LogString(trunkReq)

            reqCtx = {}

            for pluginNum, pluginId in enumerate(pluginIdList):

                st, pdu = pluginManager.processNotificationRequest(
                    pluginId, snmpEngine, pdu, trunkReq, reqCtx)

                if st == status.BREAK:
                    log.debug('plugin %s inhibits other plugins' % pluginId,
                              ctx=logCtx)
                    pluginIdList = pluginIdList[:pluginNum]
                    break

                elif st == status.DROP:
                    log.debug('plugin %s muted request' % pluginId, ctx=logCtx)
                    return

                elif st == status.RESPOND:
                    log.debug('plugin %s NOT forced immediate response' %
                              pluginId,
                              ctx=logCtx)
                    # TODO: implement immediate response for confirmed-class PDU
                    return

            # pass query to trunk

            trunkIdList = trunkReq['trunk-id-list']
            if trunkIdList is None:
                log.error('no route configured', ctx=logCtx)
                return

            for trunkId in trunkIdList:

                # TODO: pass messageProcessingModel to respond
                cbCtx = pluginIdList, trunkId, trunkReq, snmpEngine, stateReference, reqCtx

                try:
                    msgId = trunkingManager.sendReq(trunkId, trunkReq,
                                                    self.trunkCbFun, cbCtx)

                except SnmpfwdError:
                    log.error(
                        'received SNMP message, message not sent to trunk "%s" %s'
                        % (trunkId, sys.exc_info()[1]),
                        ctx=logCtx)
                    return

                log.debug(
                    'received SNMP message, forwarded as trunk message #%s' %
                    msgId,
                    ctx=logCtx)

        def trunkCbFun(self, msgId, trunkRsp, cbCtx):
            pluginIdList, trunkId, trunkReq, snmpEngine, stateReference, reqCtx = cbCtx

            for key in tuple(trunkRsp):
                if key != 'callflow-id':
                    trunkRsp['client-' + key] = trunkRsp[key]
                    del trunkRsp[key]

            trunkRsp['callflow-id'] = trunkReq['callflow-id']

            logCtx = LazyLogString(trunkReq, trunkRsp)

            if trunkRsp['client-error-indication']:
                log.info(
                    'received trunk message #%s, remote end reported error-indication "%s", NOT responding'
                    % (msgId, trunkRsp['client-error-indication']),
                    ctx=logCtx)
            else:
                if 'client-snmp-pdu' not in trunkRsp:
                    log.debug(
                        'received trunk message #%s -- unconfirmed SNMP message'
                        % msgId,
                        ctx=logCtx)
                    return

                pdu = trunkRsp['client-snmp-pdu']

                for pluginId in pluginIdList:
                    st, pdu = pluginManager.processNotificationResponse(
                        pluginId, snmpEngine, pdu, trunkReq, reqCtx)

                    if st == status.BREAK:
                        log.debug('plugin %s inhibits other plugins' %
                                  pluginId,
                                  ctx=logCtx)
                        break
                    elif st == status.DROP:
                        log.debug(
                            'received trunk message #%s, plugin %s muted response'
                            % (msgId, pluginId),
                            ctx=logCtx)
                        return

                log.debug(
                    'received trunk message #%s, forwarded as SNMP message' %
                    msgId,
                    ctx=logCtx)

                # TODO: implement response part

                # # Agent-side API complies with SMIv2
                # if messageProcessingModel == 0:
                #     PDU = rfc2576.v2ToV1(PDU, origPdu)
                #
                # statusInformation = {}
                #
                # # 3.4.3
                # try:
                #     snmpEngine.msgAndPduDsp.returnResponsePdu(
                #         snmpEngine, messageProcessingModel, securityModel,
                #         securityName, securityLevel, contextEngineId,
                #         contextName, pduVersion, rspPDU, maxSizeResponseScopedPDU,
                #         stateReference, statusInformation)
                #
                # except error.StatusInformation:
                #         log.error('processPdu: stateReference %s, statusInformation %s' % (stateReference, sys.exc_info()[1]))

    class LogString(LazyLogString):

        GROUPINGS = [
            ['callflow-id'],
            [
                'snmp-engine-id', 'snmp-transport-domain', 'snmp-bind-address',
                'snmp-bind-port', 'snmp-security-model', 'snmp-security-level',
                'snmp-security-name', 'snmp-credentials-id'
            ],
            ['snmp-context-engine-id', 'snmp-context-name', 'snmp-context-id'],
            ['snmp-pdu', 'snmp-content-id'],
            ['snmp-peer-address', 'snmp-peer-port', 'snmp-peer-id'],
            ['trunk-id'],
            ['client-snmp-pdu'],
        ]

        FORMATTERS = {
            'client-snmp-pdu': LazyLogString.prettyVarBinds,
            'snmp-pdu': LazyLogString.prettyVarBinds,
        }

    def securityAuditObserver(snmpEngine, execpoint, variables, cbCtx):
        securityModel = variables.get('securityModel', 0)

        logMsg = 'SNMPv%s auth failure' % securityModel
        logMsg += ' at %s:%s' % variables['transportAddress'].getLocalAddress()
        logMsg += ' from %s:%s' % variables['transportAddress']

        statusInformation = variables.get('statusInformation', {})

        if securityModel in (1, 2):
            logMsg += ' using snmp-community-name "%s"' % statusInformation.get(
                'communityName', '?')
        elif securityModel == 3:
            logMsg += ' using snmp-usm-user "%s"' % statusInformation.get(
                'msgUserName', '?')

        try:
            logMsg += ': %s' % statusInformation['errorIndication']

        except KeyError:
            pass

        log.error(logMsg)

    def requestObserver(snmpEngine, execpoint, variables, cbCtx):

        trunkReq = {
            'callflow-id': '%10.10x' % random.randint(0, 0xffffffffff),
            'snmp-engine-id': snmpEngine.snmpEngineID,
            'snmp-transport-domain': variables['transportDomain'],
            'snmp-peer-address': variables['transportAddress'][0],
            'snmp-peer-port': variables['transportAddress'][1],
            'snmp-bind-address':
            variables['transportAddress'].getLocalAddress()[0],
            'snmp-bind-port':
            variables['transportAddress'].getLocalAddress()[1],
            'snmp-security-model': variables['securityModel'],
            'snmp-security-level': variables['securityLevel'],
            'snmp-security-name': variables['securityName'],
            'snmp-context-engine-id': variables['contextEngineId'],
            'snmp-context-name': variables['contextName'],
        }

        trunkReq['snmp-credentials-id'] = macro.expandMacro(
            credIdMap.get(
                (str(snmpEngine.snmpEngineID), variables['transportDomain'],
                 variables['securityModel'], variables['securityLevel'],
                 str(variables['securityName']))), trunkReq)

        k = '#'.join([
            str(x)
            for x in (variables['contextEngineId'], variables['contextName'])
        ])
        for x, y in contextIdList:
            if y.match(k):
                trunkReq['snmp-context-id'] = macro.expandMacro(x, trunkReq)
                break
            else:
                trunkReq['snmp-context-id'] = None

        addr = '%s:%s#%s:%s' % (
            variables['transportAddress'][0], variables['transportAddress'][1],
            variables['transportAddress'].getLocalAddress()[0],
            variables['transportAddress'].getLocalAddress()[1])

        for pat, peerId in peerIdMap.get(str(variables['transportDomain']),
                                         ()):
            if pat.match(addr):
                trunkReq['snmp-peer-id'] = macro.expandMacro(peerId, trunkReq)
                break
        else:
            trunkReq['snmp-peer-id'] = None

        pdu = variables['pdu']
        if pdu.tagSet == v1.TrapPDU.tagSet:
            pdu = rfc2576.v1ToV2(pdu)
            v2c.apiTrapPDU.setDefaults(pdu)

        k = '#'.join([
            snmpPduTypesMap.get(variables['pdu'].tagSet, '?'),
            '|'.join([str(x[0]) for x in v2c.apiTrapPDU.getVarBinds(pdu)])
        ])

        for x, y in contentIdList:
            if y.match(k):
                trunkReq['snmp-content-id'] = macro.expandMacro(x, trunkReq)
                break
            else:
                trunkReq['snmp-content-id'] = None

        trunkReq['plugins-list'] = pluginIdMap.get(
            (trunkReq['snmp-credentials-id'], trunkReq['snmp-context-id'],
             trunkReq['snmp-peer-id'], trunkReq['snmp-content-id']), [])
        trunkReq['trunk-id-list'] = trunkIdMap.get(
            (trunkReq['snmp-credentials-id'], trunkReq['snmp-context-id'],
             trunkReq['snmp-peer-id'], trunkReq['snmp-content-id']))

        cbCtx.clear()
        cbCtx.update(trunkReq)

    #
    # main script starts here
    #

    helpMessage = """\
        Usage: %s [--help]
            [--version ]
            [--debug-snmp=<%s>]
            [--debug-asn1=<%s>]
            [--daemonize]
            [--process-user=<uname>] [--process-group=<gname>]
            [--pid-file=<file>]
            [--logging-method=<%s[:args>]>]
            [--log-level=<%s>]
            [--config-file=<file>]""" % (sys.argv[0], '|'.join([
        x for x in pysnmp_debug.flagMap.keys() if x != 'mibview'
    ]), '|'.join([x for x in pyasn1_debug.flagMap.keys()]), '|'.join(
        log.methodsMap.keys()), '|'.join(log.levelsMap))

    try:
        opts, params = getopt.getopt(sys.argv[1:], 'hv', [
            'help', 'version', 'debug=', 'debug-snmp=', 'debug-asn1=',
            'daemonize', 'process-user='******'process-group=', 'pid-file=',
            'logging-method=', 'log-level=', 'config-file='
        ])

    except Exception:
        sys.stderr.write('ERROR: %s\r\n%s\r\n' %
                         (sys.exc_info()[1], helpMessage))
        return

    if params:
        sys.stderr.write('ERROR: extra arguments supplied %s\r\n%s\r\n' %
                         (params, helpMessage))
        return

    pidFile = ''
    cfgFile = CONFIG_FILE
    foregroundFlag = True
    procUser = procGroup = None

    loggingMethod = ['stderr']
    loggingLevel = None

    for opt in opts:
        if opt[0] == '-h' or opt[0] == '--help':
            sys.stderr.write("""\
        Synopsis:
          SNMP Proxy Forwarder: server part. Receives SNMP requests at one or many
          built-in SNMP Agents and routes them to encrypted trunks established with
          Forwarder's Manager part(s) running elsewhere.
          Can implement complex routing logic through analyzing parts of SNMP messages
          and matching them against proxying rules.

        Documentation:
          http://snmpfwd.sourceforge.io/

    %s
    """ % helpMessage)
            return
        if opt[0] == '-v' or opt[0] == '--version':
            import snmpfwd
            import pysnmp
            import pyasn1
            sys.stderr.write("""\
        SNMP Proxy Forwarder version %s, written by Ilya Etingof <*****@*****.**>
        Using foundation libraries: pysnmp %s, pyasn1 %s.
        Python interpreter: %s
        Software documentation and support at https://github.com/etingof/snmpfwd
        %s
        """ % (snmpfwd.__version__, hasattr(pysnmp, '__version__')
               and pysnmp.__version__ or 'unknown',
               hasattr(pyasn1, '__version__') and pyasn1.__version__
               or 'unknown', sys.version, helpMessage))
            return
        elif opt[0] == '--debug-snmp':
            pysnmp_debug.setLogger(
                pysnmp_debug.Debug(*opt[1].split(','),
                                   **dict(loggerName=PROGRAM_NAME +
                                          '.pysnmp')))
        elif opt[0] == '--debug-asn1':
            pyasn1_debug.setLogger(
                pyasn1_debug.Debug(*opt[1].split(','),
                                   **dict(loggerName=PROGRAM_NAME +
                                          '.pyasn1')))
        elif opt[0] == '--daemonize':
            foregroundFlag = False
        elif opt[0] == '--process-user':
            procUser = opt[1]
        elif opt[0] == '--process-group':
            procGroup = opt[1]
        elif opt[0] == '--pid-file':
            pidFile = opt[1]
        elif opt[0] == '--logging-method':
            loggingMethod = opt[1].split(':')
        elif opt[0] == '--log-level':
            loggingLevel = opt[1]
        elif opt[0] == '--config-file':
            cfgFile = opt[1]

    try:
        log.setLogger(PROGRAM_NAME, *loggingMethod, **dict(force=True))

        if loggingLevel:
            log.setLevel(loggingLevel)

    except SnmpfwdError:
        sys.stderr.write('%s\r\n%s\r\n' % (sys.exc_info()[1], helpMessage))
        return

    try:
        cfgTree = cparser.Config().load(cfgFile)
    except SnmpfwdError:
        log.error('configuration parsing error: %s' % sys.exc_info()[1])
        return

    if cfgTree.getAttrValue('program-name', '', default=None) != PROGRAM_NAME:
        log.error('config file %s does not match program name %s' %
                  (cfgFile, PROGRAM_NAME))
        return

    if cfgTree.getAttrValue('config-version', '',
                            default=None) != CONFIG_VERSION:
        log.error(
            'config file %s version is not compatible with program version %s'
            % (cfgFile, CONFIG_VERSION))
        return

    random.seed()

    gCurrentRequestContext = {}

    credIdMap = {}
    peerIdMap = {}
    contextIdList = []
    contentIdList = []
    pluginIdMap = {}
    trunkIdMap = {}
    engineIdMap = {}

    transportDispatcher = AsynsockDispatcher()
    transportDispatcher.registerRoutingCbFun(lambda td, t, d: td)
    transportDispatcher.setSocketMap()  # use global asyncore socket map

    #
    # Initialize plugin modules
    #

    pluginManager = PluginManager(macro.expandMacros(
        cfgTree.getAttrValue('plugin-modules-path-list',
                             '',
                             default=[],
                             vector=True),
        {'config-dir': os.path.dirname(cfgFile)}),
                                  progId=PROGRAM_NAME,
                                  apiVer=PLUGIN_API_VERSION)

    for pluginCfgPath in cfgTree.getPathsToAttr('plugin-id'):
        pluginId = cfgTree.getAttrValue('plugin-id', *pluginCfgPath)
        pluginMod = cfgTree.getAttrValue('plugin-module', *pluginCfgPath)
        pluginOptions = macro.expandMacros(
            cfgTree.getAttrValue('plugin-options', *pluginCfgPath,
                                 **dict(default=[], vector=True)),
            {'config-dir': os.path.dirname(cfgFile)})

        log.info(
            'configuring plugin ID %s (at %s) from module %s with options %s...'
            % (pluginId, '.'.join(pluginCfgPath), pluginMod,
               ', '.join(pluginOptions) or '<none>'))

        try:
            pluginManager.loadPlugin(pluginId, pluginMod, pluginOptions)

        except SnmpfwdError:
            log.error('plugin %s not loaded: %s' %
                      (pluginId, sys.exc_info()[1]))
            return

    for configEntryPath in cfgTree.getPathsToAttr('snmp-credentials-id'):
        credId = cfgTree.getAttrValue('snmp-credentials-id', *configEntryPath)
        configKey = []
        log.info('configuring snmp-credentials %s (at %s)...' %
                 (credId, '.'.join(configEntryPath)))

        engineId = cfgTree.getAttrValue('snmp-engine-id', *configEntryPath)

        if engineId in engineIdMap:
            snmpEngine, snmpContext, snmpEngineMap = engineIdMap[engineId]
            log.info('using engine-id %s' %
                     snmpEngine.snmpEngineID.prettyPrint())
        else:
            snmpEngine = engine.SnmpEngine(snmpEngineID=engineId)
            snmpContext = context.SnmpContext(snmpEngine)
            snmpEngineMap = {'transportDomain': {}, 'securityName': {}}

            snmpEngine.observer.registerObserver(
                securityAuditObserver,
                'rfc2576.prepareDataElements:sm-failure',
                'rfc3412.prepareDataElements:sm-failure',
                cbCtx=gCurrentRequestContext)

            snmpEngine.observer.registerObserver(
                requestObserver,
                'rfc3412.receiveMessage:request',
                cbCtx=gCurrentRequestContext)

            CommandResponder(snmpEngine, snmpContext)

            NotificationReceiver(snmpEngine, None)

            engineIdMap[engineId] = snmpEngine, snmpContext, snmpEngineMap

            log.info('new engine-id %s' %
                     snmpEngine.snmpEngineID.prettyPrint())

        configKey.append(str(snmpEngine.snmpEngineID))

        transportDomain = cfgTree.getAttrValue('snmp-transport-domain',
                                               *configEntryPath)
        transportDomain = rfc1902.ObjectName(transportDomain)

        if transportDomain in snmpEngineMap['transportDomain']:
            h, p, transportDomain = snmpEngineMap['transportDomain'][
                transportDomain]
            log.info('using transport endpoint %s:%s, transport ID %s' %
                     (h, p, transportDomain))
        else:
            if transportDomain[:len(udp.domainName)] == udp.domainName:
                transport = udp.UdpTransport()
            elif transportDomain[:len(udp6.domainName)] == udp6.domainName:
                transport = udp6.Udp6Transport()
            else:
                log.error('unknown transport domain %s' % (transportDomain, ))
                return

            h, p = cfgTree.getAttrValue('snmp-bind-address',
                                        *configEntryPath).split(':', 1)

            snmpEngine.registerTransportDispatcher(transportDispatcher,
                                                   transportDomain)

            transportOptions = cfgTree.getAttrValue(
                'snmp-transport-options', *configEntryPath,
                **dict(default=[], vector=True))

            t = transport.openServerMode((h, int(p)))

            if 'transparent-proxy' in transportOptions:
                t.enablePktInfo()
                t.enableTransparent()
            elif 'virtual-interface' in transportOptions:
                t.enablePktInfo()

            config.addSocketTransport(snmpEngine, transportDomain, t)

            snmpEngineMap['transportDomain'][
                transportDomain] = h, p, transportDomain

            log.info(
                'new transport endpoint %s:%s, options %s, transport ID %s' %
                (h, p, transportOptions and '/'.join(transportOptions)
                 or '<none>', transportDomain))

        configKey.append(transportDomain)

        securityModel = cfgTree.getAttrValue('snmp-security-model',
                                             *configEntryPath)
        securityModel = rfc1902.Integer(securityModel)
        securityLevel = cfgTree.getAttrValue('snmp-security-level',
                                             *configEntryPath)
        securityLevel = rfc1902.Integer(securityLevel)
        securityName = cfgTree.getAttrValue('snmp-security-name',
                                            *configEntryPath)

        if securityModel in (1, 2):
            if securityName in snmpEngineMap['securityName']:
                if snmpEngineMap['securityName'][
                        securityModel] == securityModel:
                    log.info('using security-name %s' % securityName)
                else:
                    raise SnmpfwdError(
                        'snmp-security-name %s already in use at snmp-security-model %s'
                        % (securityName, securityModel))
            else:
                communityName = cfgTree.getAttrValue('snmp-community-name',
                                                     *configEntryPath)
                config.addV1System(snmpEngine,
                                   securityName,
                                   communityName,
                                   securityName=securityName)
                log.info(
                    'new community-name %s, security-model %s, security-name %s, security-level %s'
                    % (communityName, securityModel, securityName,
                       securityLevel))
                snmpEngineMap['securityName'][securityName] = securityModel

            configKey.append(securityModel)
            configKey.append(securityLevel)
            configKey.append(securityName)

        elif securityModel == 3:
            if securityName in snmpEngineMap['securityName']:
                log.info('using USM security-name: %s' % securityName)
            else:
                usmUser = cfgTree.getAttrValue('snmp-usm-user',
                                               *configEntryPath)
                log.info(
                    'new USM user %s, security-model %s, security-level %s, security-name %s'
                    % (usmUser, securityModel, securityLevel, securityName))

                if securityLevel in (2, 3):
                    usmAuthProto = cfgTree.getAttrValue(
                        'snmp-usm-auth-protocol', *configEntryPath,
                        **dict(default=config.usmHMACMD5AuthProtocol))
                    usmAuthProto = rfc1902.ObjectName(usmAuthProto)
                    usmAuthKey = cfgTree.getAttrValue('snmp-usm-auth-key',
                                                      *configEntryPath)
                    log.info(
                        'new USM authentication key: %s, authentication protocol: %s'
                        % (usmAuthKey, usmAuthProto))

                    if securityLevel == 3:
                        usmPrivProto = cfgTree.getAttrValue(
                            'snmp-usm-priv-protocol', *configEntryPath,
                            **dict(default=config.usmDESPrivProtocol))
                        usmPrivProto = rfc1902.ObjectName(usmPrivProto)
                        usmPrivKey = cfgTree.getAttrValue(
                            'snmp-usm-priv-key', *configEntryPath,
                            **dict(default=None))
                        log.info(
                            'new USM encryption key: %s, encryption protocol: %s'
                            % (usmPrivKey, usmPrivProto))

                        config.addV3User(snmpEngine, usmUser, usmAuthProto,
                                         usmAuthKey, usmPrivProto, usmPrivKey)

                    else:
                        config.addV3User(snmpEngine, usmUser, usmAuthProto,
                                         usmAuthKey)

                else:
                    config.addV3User(snmpEngine, usmUser)

                snmpEngineMap['securityName'][securityName] = securityModel

            configKey.append(securityModel)
            configKey.append(securityLevel)
            configKey.append(securityName)

        else:
            raise SnmpfwdError('unknown snmp-security-model: %s' %
                               securityModel)

        configKey = tuple(configKey)
        if configKey in credIdMap:
            log.error(
                'ambiguous configuration for key snmp-credentials-id=%s at %s'
                % (credId, '.'.join(configEntryPath)))
            return

        credIdMap[configKey] = credId

    duplicates = {}

    for peerCfgPath in cfgTree.getPathsToAttr('snmp-peer-id'):
        peerId = cfgTree.getAttrValue('snmp-peer-id', *peerCfgPath)
        if peerId in duplicates:
            log.error(
                'duplicate snmp-peer-id=%s at %s and %s' %
                (peerId, '.'.join(peerCfgPath), '.'.join(duplicates[peerId])))
            return

        duplicates[peerId] = peerCfgPath

        log.info('configuring peer ID %s (at %s)...' %
                 (peerId, '.'.join(peerCfgPath)))
        transportDomain = cfgTree.getAttrValue('snmp-transport-domain',
                                               *peerCfgPath)
        if transportDomain not in peerIdMap:
            peerIdMap[transportDomain] = []
        for peerAddress in cfgTree.getAttrValue(
                'snmp-peer-address-pattern-list', *peerCfgPath,
                **dict(vector=True)):
            for bindAddress in cfgTree.getAttrValue(
                    'snmp-bind-address-pattern-list', *peerCfgPath,
                    **dict(vector=True)):
                peerIdMap[transportDomain].append(
                    (re.compile(peerAddress + '#' + bindAddress), peerId))

    duplicates = {}

    for contextCfgPath in cfgTree.getPathsToAttr('snmp-context-id'):
        contextId = cfgTree.getAttrValue('snmp-context-id', *contextCfgPath)
        if contextId in duplicates:
            log.error('duplicate snmp-context-id=%s at %s and %s' %
                      (contextId, '.'.join(contextCfgPath), '.'.join(
                          duplicates[contextId])))
            return

        duplicates[contextId] = contextCfgPath

        k = '#'.join((cfgTree.getAttrValue('snmp-context-engine-id-pattern',
                                           *contextCfgPath),
                      cfgTree.getAttrValue('snmp-context-name-pattern',
                                           *contextCfgPath)))

        log.info('configuring context ID %s (at %s), composite key: %s' %
                 (contextId, '.'.join(contextCfgPath), k))

        contextIdList.append((contextId, re.compile(k)))

    duplicates = {}

    for contentCfgPath in cfgTree.getPathsToAttr('snmp-content-id'):
        contentId = cfgTree.getAttrValue('snmp-content-id', *contentCfgPath)
        if contentId in duplicates:
            log.error('duplicate snmp-content-id=%s at %s and %s' %
                      (contentId, '.'.join(contentCfgPath), '.'.join(
                          duplicates[contentId])))
            return

        duplicates[contentId] = contentCfgPath

        for x in cfgTree.getAttrValue('snmp-pdu-oid-prefix-pattern-list',
                                      *contentCfgPath, **dict(vector=True)):
            k = '#'.join([
                cfgTree.getAttrValue('snmp-pdu-type-pattern', *contentCfgPath),
                x
            ])

            log.info('configuring content ID %s (at %s), composite key: %s' %
                     (contentId, '.'.join(contentCfgPath), k))

            contentIdList.append((contentId, re.compile(k)))

    del duplicates

    for pluginCfgPath in cfgTree.getPathsToAttr('using-plugin-id-list'):
        pluginIdList = cfgTree.getAttrValue('using-plugin-id-list',
                                            *pluginCfgPath,
                                            **dict(vector=True))
        log.info('configuring plugin ID(s) %s (at %s)...' %
                 (','.join(pluginIdList), '.'.join(pluginCfgPath)))
        for credId in cfgTree.getAttrValue('matching-snmp-credentials-id-list',
                                           *pluginCfgPath,
                                           **dict(vector=True)):
            for peerId in cfgTree.getAttrValue('matching-snmp-peer-id-list',
                                               *pluginCfgPath,
                                               **dict(vector=True)):
                for contextId in cfgTree.getAttrValue(
                        'matching-snmp-context-id-list', *pluginCfgPath,
                        **dict(vector=True)):
                    for contentId in cfgTree.getAttrValue(
                            'matching-snmp-content-id-list', *pluginCfgPath,
                            **dict(vector=True)):
                        k = credId, contextId, peerId, contentId
                        if k in pluginIdMap:
                            log.error(
                                'duplicate snmp-credentials-id %s, snmp-context-id %s, snmp-peer-id %s, snmp-content-id %s at plugin-id(s) %s'
                                % (credId, contextId, peerId, contentId,
                                   ','.join(pluginIdList)))
                            return
                        else:
                            log.info(
                                'configuring plugin(s) %s (at %s), composite key: %s'
                                % (','.join(pluginIdList),
                                   '.'.join(pluginCfgPath), '/'.join(k)))

                            for pluginId in pluginIdList:
                                if not pluginManager.hasPlugin(pluginId):
                                    log.error(
                                        'undefined plugin ID %s referenced at %s'
                                        % (pluginId, '.'.join(pluginCfgPath)))
                                    return

                            pluginIdMap[k] = pluginIdList

    for routeCfgPath in cfgTree.getPathsToAttr('using-trunk-id-list'):
        trunkIdList = cfgTree.getAttrValue('using-trunk-id-list',
                                           *routeCfgPath, **dict(vector=True))
        log.info('configuring destination trunk ID(s) %s (at %s)...' %
                 (','.join(trunkIdList), '.'.join(routeCfgPath)))
        for credId in cfgTree.getAttrValue('matching-snmp-credentials-id-list',
                                           *routeCfgPath, **dict(vector=True)):
            for peerId in cfgTree.getAttrValue('matching-snmp-peer-id-list',
                                               *routeCfgPath,
                                               **dict(vector=True)):
                for contextId in cfgTree.getAttrValue(
                        'matching-snmp-context-id-list', *routeCfgPath,
                        **dict(vector=True)):
                    for contentId in cfgTree.getAttrValue(
                            'matching-snmp-content-id-list', *routeCfgPath,
                            **dict(vector=True)):
                        k = credId, contextId, peerId, contentId
                        if k in trunkIdMap:
                            log.error(
                                'duplicate snmp-credentials-id %s, snmp-context-id %s, snmp-peer-id %s, snmp-content-id %s at trunk-id(s) %s'
                                % (credId, contextId, peerId, contentId,
                                   ','.join(trunkIdList)))
                            return
                        else:
                            trunkIdMap[k] = trunkIdList

                        log.info(
                            'configuring trunk routing to %s (at %s), composite key: %s'
                            % (','.join(trunkIdList), '.'.join(routeCfgPath),
                               '/'.join(k)))

    def dataCbFun(trunkId, msgId, msg):
        log.debug('message ID %s received from trunk %s' % (msgId, trunkId))

    trunkingManager = TrunkingManager(dataCbFun)

    def getTrunkAddr(a, port=0):
        f = lambda h, p=port: (h, int(p))
        try:
            return f(*a.split(':'))

        except Exception:
            raise SnmpfwdError('improper IPv4 endpoint %s' % a)

    for trunkCfgPath in cfgTree.getPathsToAttr('trunk-id'):
        trunkId = cfgTree.getAttrValue('trunk-id', *trunkCfgPath)
        secret = cfgTree.getAttrValue('trunk-crypto-key', *trunkCfgPath,
                                      **dict(default=''))
        secret = secret and (secret * ((16 // len(secret)) + 1))[:16]
        log.info('configuring trunk ID %s (at %s)...' %
                 (trunkId, '.'.join(trunkCfgPath)))
        connectionMode = cfgTree.getAttrValue('trunk-connection-mode',
                                              *trunkCfgPath)
        if connectionMode == 'client':
            trunkingManager.addClient(
                trunkId,
                getTrunkAddr(
                    cfgTree.getAttrValue('trunk-bind-address', *trunkCfgPath)),
                getTrunkAddr(
                    cfgTree.getAttrValue('trunk-peer-address', *trunkCfgPath),
                    30201),
                cfgTree.getAttrValue('trunk-ping-period',
                                     *trunkCfgPath,
                                     default=0,
                                     expect=int), secret)
            log.info(
                'new trunking client from %s to %s' %
                (cfgTree.getAttrValue('trunk-bind-address', *trunkCfgPath),
                 cfgTree.getAttrValue('trunk-peer-address', *trunkCfgPath)))
        if connectionMode == 'server':
            trunkingManager.addServer(
                getTrunkAddr(
                    cfgTree.getAttrValue('trunk-bind-address', *trunkCfgPath),
                    30201),
                cfgTree.getAttrValue('trunk-ping-period',
                                     *trunkCfgPath,
                                     default=0,
                                     expect=int), secret)
            log.info(
                'new trunking server at %s' %
                (cfgTree.getAttrValue('trunk-bind-address', *trunkCfgPath)))

    transportDispatcher.registerTimerCbFun(trunkingManager.setupTrunks,
                                           random.randrange(1, 5))
    transportDispatcher.registerTimerCbFun(trunkingManager.monitorTrunks,
                                           random.randrange(1, 5))

    try:
        daemon.dropPrivileges(procUser, procGroup)

    except Exception:
        log.error('can not drop privileges: %s' % sys.exc_info()[1])
        return

    if not foregroundFlag:
        try:
            daemon.daemonize(pidFile)

        except Exception:
            log.error('can not daemonize process: %s' % sys.exc_info()[1])
            return

    # Run mainloop

    log.info('starting I/O engine...')

    transportDispatcher.jobStarted(1)  # server job would never finish

    # Python 2.4 does not support the "finally" clause

    while True:
        try:
            transportDispatcher.runDispatcher()

        except (PySnmpError, SnmpfwdError, socket.error):
            log.error(str(sys.exc_info()[1]))
            continue

        except Exception:
            transportDispatcher.closeDispatcher()
            raise