Exemple #1
0
    def handle_connect(self):
        if self.isUp:
            return
        self.isUp = True

        if self.__announcementData:
            self.send(self.__announcementData)
            self.__announcementData = null
            log.debug('%s: trunk announcement sent' % (self,))

        log.info('%s: client is now connected' % (self,))
Exemple #2
0
        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)
Exemple #3
0
        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('trunk message #%s, SNMP response error: %s' %
                              (msgId, sys.exc_info()[1]),
                              ctx=logCtx)

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

            self.releaseStateInformation(stateReference)
Exemple #4
0
    def snmpCbFun(snmpEngine, sendRequestHandle, errorIndication, rspPDU,
                  cbCtx):

        trunkId, msgId, trunkReq, pluginIdList, reqCtx = cbCtx

        trunkRsp = {
            'callflow-id': trunkReq['callflow-id'],
            'snmp-pdu': rspPDU,
        }

        logCtx = LogString(trunkRsp)

        if errorIndication:
            log.info('received SNMP error-indication "%s"' % errorIndication,
                     ctx=logCtx)
            trunkRsp['error-indication'] = errorIndication

        if rspPDU:
            reqPdu = trunkReq['server-snmp-pdu']

            for pluginId in pluginIdList:
                if reqPdu.tagSet in rfc3411.notificationClassPDUs:
                    st, rspPDU = pluginManager.processNotificationResponse(
                        pluginId, snmpEngine, rspPDU, trunkReq, reqCtx)

                elif reqPdu.tagSet not in rfc3411.unconfirmedClassPDUs:
                    st, rspPDU = pluginManager.processCommandResponse(
                        pluginId, snmpEngine, rspPDU, trunkReq, reqCtx)
                else:
                    log.error('ignoring unsupported PDU', ctx=logCtx)
                    break

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

                elif st == status.DROP:
                    log.debug(
                        'received SNMP %s, plugin %s muted response' %
                        (errorIndication and 'error' or 'response', pluginId),
                        ctx=logCtx)
                    trunkRsp['snmp-pdu'] = None
                    break

        try:
            trunkingManager.sendRsp(trunkId, msgId, trunkRsp)

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

        log.debug('received SNMP %s message, forwarded as trunk message #%s' %
                  (errorIndication and 'error' or 'response', msgId),
                  ctx=logCtx)
Exemple #5
0
            for lineNo, line in enumerate(open(configFile).readlines()):
                line = line.strip()

                if not line or line.startswith('#'):
                    continue

                try:
                    oidPatt, valPatt, valRepl, replCount = shlex.split(line)

                except ValueError:
                    raise SnmpfwdError('%s: syntax error at %s:%d: %s' %
                                       (PLUGIN_NAME, configFile, lineNo + 1,
                                        sys.exc_info()[1]))

                debug(
                    '%s: for OIDs like "%s" and values matching "%s" rewrite value into "%s" (max %s times)'
                    % (PLUGIN_NAME, oidPatt, valPatt, valRepl, replCount))

                rewriteList.append(
                    (re.compile(oidPatt), re.compile(valPatt), valRepl,
                     int(replCount)))

        except Exception:
            raise SnmpfwdError('%s: config file load failure: %s' %
                               (PLUGIN_NAME, sys.exc_info()[1]))

info('%s: plugin initialization complete' % PLUGIN_NAME)


def processCommandResponse(pluginId, snmpEngine, pdu, trunkMsg, reqCtx):
    varBinds = []
Exemple #6
0
 def dataCbFun(trunkId, msgId, msg):
     log.debug('message ID %s received from trunk %s' % (msgId, trunkId))
Exemple #7
0
        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)
Exemple #8
0
        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)
Exemple #9
0
def processCommandRequest(pluginId, snmpEngine, pdu, trunkMsg, reqCtx):

    reqOids = []

    reqCtx['req-oids'] = reqOids
    reqCtx['req-pdu'] = pdu

    if pdu.tagSet in (v2c.GetRequestPDU.tagSet, v2c.SetRequestPDU.tagSet):

        allDenied = True

        deniedOids = []

        for varBindIdx, varBind in enumerate(v2c.apiPDU.getVarBindList(pdu)):

            oid, val = v2c.apiVarBind.getOIDVal(varBind)

            oid = tuple(oid)

            skip, aclIdx = findAcl(oid)

            # skipped to the next OID
            if skip != oid:
                aclIdx = None

            # OID went out of range
            if aclIdx is None:
                # report OIDs we are sending errors for
                if logDenials:
                    deniedOids.append(str(varBind[0]))
            else:
                allDenied = False

            reqOids.append((oid, varBindIdx, aclIdx))

        if logDenials and deniedOids:
            denialMsg = formatDenialMsg(pdu, trunkMsg)
            denialMsg += ' OIDs ' + ', '.join(deniedOids)
            denialMsg += ' denied'
            error(denialMsg)

        reqVarBinds = v2c.VarBindList()

        if allDenied:
            pdu = v2c.apiPDU.getResponse(pdu)

            for oid, _, _ in reqOids:
                varBind = v2c.VarBind()
                v2c.apiVarBind.setOIDVal(varBind, (oid, noSuchInstance))
                reqVarBinds.append(varBind)

            nextAction = status.RESPOND

        else:
            for oid, _, aclIdx in reqOids:
                if aclIdx is None:
                    continue
                varBind = v2c.VarBind()
                v2c.apiVarBind.setOIDVal(varBind, (oid, null))
                reqVarBinds.append(varBind)

            nextAction = status.NEXT

        v2c.apiPDU.setVarBindList(pdu, reqVarBinds)

        return nextAction, pdu

    elif pdu.tagSet == v2c.GetNextRequestPDU.tagSet:

        allDenied = True

        skippedOids = []

        for varBindIdx, varBind in enumerate(v2c.apiPDU.getVarBindList(pdu)):

            oid, val = v2c.apiVarBind.getOIDVal(varBind)

            oid = tuple(oid)

            skip, aclIdx = findAcl(oid, nextOid=True)

            if logDenials and oid != skip:
                skippedOids.append((oid, skip))

            oid = skip

            # OID went out of range
            if aclIdx is not None:
                allDenied = False

            reqOids.append((oid, varBindIdx, aclIdx))

        if logDenials and skippedOids:
            denialMsg = formatDenialMsg(pdu, trunkMsg)
            denialMsg += ' ' + ', '.join([
                '%s not in range skipping to %s' %
                (v2c.ObjectIdentifier(x[0]), v2c.ObjectIdentifier(x[1]))
                for x in skippedOids
            ])
            info(denialMsg)

        reqVarBinds = v2c.VarBindList()

        if allDenied:
            pdu = v2c.apiPDU.getResponse(pdu)

            for oid, _, _ in reqOids:
                varBind = v2c.VarBind()
                v2c.apiVarBind.setOIDVal(varBind, (oid, endOfMibView))
                reqVarBinds.append(varBind)

            nextAction = status.RESPOND

        else:
            for oid, _, aclIdx in reqOids:
                if aclIdx is None:
                    continue
                varBind = v2c.VarBind()
                v2c.apiVarBind.setOIDVal(varBind, (oid, null))
                reqVarBinds.append(varBind)

            nextAction = status.NEXT

        v2c.apiPDU.setVarBindList(pdu, reqVarBinds)

        return nextAction, pdu

    elif pdu.tagSet == v2c.GetBulkRequestPDU.tagSet:

        nonRepeaters = v2c.apiBulkPDU.getNonRepeaters(pdu)
        maxRepeaters = v2c.apiBulkPDU.getMaxRepetitions(pdu)

        nonRepOids = []
        linearizedOids = []
        repOids = []

        linearizedOidsMap = {}
        repeatersOidMap = {}

        reqCtx['linearized-oids-map'] = linearizedOidsMap
        reqCtx['repeaters-oids-map'] = repeatersOidMap

        reqCtx['non-repeaters'] = nonRepeaters

        allDenied = True

        skippedOids = []

        for varBindIdx, varBind in enumerate(
                v2c.apiBulkPDU.getVarBindList(pdu)):

            oid, val = v2c.apiVarBind.getOIDVal(varBind)

            oid = tuple(oid)

            skip, aclIdx = findAcl(oid, nextOid=True)

            if logDenials and oid != skip:
                skippedOids.append((oid, skip))

            oid = skip

            # original request var-binds
            reqOids.append((oid, varBindIdx, aclIdx))

            # OID went beyond all ranges
            if aclIdx is None:
                continue

            allDenied = False

            # original request non-repeaters
            if varBindIdx < nonRepeaters:
                nonRepOids.append((oid, varBindIdx, aclIdx))
                continue

            # original request repeaters
            skip, begin, end = oidsList[aclIdx]

            # move single-OID ranges from repeaters into non-repeaters
            startIdx = len(nonRepOids) + len(linearizedOids)
            endIdx = startIdx

            if begin == end:
                while endIdx - startIdx < maxRepeaters:
                    linearizedOids.append((oid, varBindIdx, aclIdx))
                    endIdx += 1
                    aclIdx += 1
                    if aclIdx >= len(endOids):
                        break
                    oid, begin, end = oidsList[aclIdx]
                    if begin != end:
                        break

                linearizedOidsMap[varBindIdx] = startIdx, endIdx

                debug(
                    '%s: repeating OID #%d (%s) converted into non-repeaters #%d..%d'
                    % (PLUGIN_NAME, varBindIdx, varBind[0], startIdx,
                       endIdx - 1))

                continue

            # proceed with original repeaters
            repeatersOidMap[varBindIdx] = len(repOids)

            repOids.append((oid, varBindIdx, aclIdx))

        if logDenials and skippedOids:
            denialMsg = formatDenialMsg(pdu, trunkMsg)
            denialMsg += ' ' + ', '.join([
                '%s not in range skipping to %s' %
                (v2c.ObjectIdentifier(x[0]), v2c.ObjectIdentifier(x[1]))
                for x in skippedOids
            ])
            info(denialMsg)

        # assemble new var-binds
        reqVarBinds = v2c.VarBindList()

        if allDenied:
            pdu = v2c.apiBulkPDU.getResponse(pdu)

            for oid, _, _ in reqOids:
                varBind = v2c.VarBind()
                v2c.apiVarBind.setOIDVal(varBind, (oid, endOfMibView))
                reqVarBinds.append(varBind)

            nextAction = status.RESPOND

        else:

            for varBindIdx in repeatersOidMap:
                repeatersOidMap[varBindIdx] += len(nonRepOids) + len(
                    linearizedOids)

            for oid, varBindIdx, aclIdx in nonRepOids + linearizedOids + repOids:
                if aclIdx is None:
                    continue

                varBind = v2c.VarBind()
                v2c.apiVarBind.setOIDVal(varBind, (oid, null))
                reqVarBinds.append(varBind)

            v2c.apiBulkPDU.setNonRepeaters(pdu,
                                           nonRepeaters + len(linearizedOids))

            nextAction = status.NEXT

        v2c.apiPDU.setVarBindList(pdu, reqVarBinds)

        return nextAction, pdu

    else:
        return status.NEXT, pdu
Exemple #10
0
                    if begin <= prev_begin:
                        raise SnmpfwdError(
                            '%s: begin OID %s not increasing at %s' %
                            (PLUGIN_NAME, begin, configFile))
                    if end <= prev_end:
                        raise SnmpfwdError(
                            '%s: end OID %s not increasing at %s' %
                            (PLUGIN_NAME, end, configFile))
                    if begin < prev_end:
                        raise SnmpfwdError(
                            '%s: non-adjacent end OID %s followed by begin OID %s at %s'
                            % (PLUGIN_NAME, prev_end, begin, configFile))

                idx += 1

                debug('%s: #%d skip to %s allow from %s to %s' %
                      (PLUGIN_NAME, idx, skip, begin, end))

            # cast to built-in tuple type for better comparison performance down the road
            oidsList = [(tuple(skip), tuple(begin), tuple(end))
                        for skip, begin, end in oidsList]

            # we use this for pivoting dichotomy search
            endOids = [x[2] for x in oidsList]

        except Exception:
            raise SnmpfwdError('%s: config file load failure: %s' %
                               (PLUGIN_NAME, sys.exc_info()[1]))

    elif optionName == 'log-denials':
        logDenials = optionValue == 'true'
        info('%s: will log denied OIDs' % PLUGIN_NAME)
Exemple #11
0
        if method == 'file':

            rotation = config.get('file', 'rotation')
            if rotation == 'timed':
                handler = handlers.TimedRotatingFileHandler(
                    config.get('file', 'destination'),
                    config.get('file', 'timescale'),
                    int(config.get('file', 'interval')),
                    int(config.get('file', 'backupcount'))
                )
            else:
                raise SnmpfwdError('%s: unknown rotation method %s at %s' % (PLUGIN_NAME, rotation, configFile))
        else:
            raise SnmpfwdError('%s: unknown logging method %s at %s' % (PLUGIN_NAME, method, configFile))

        debug('%s: using %s logging method' % (PLUGIN_NAME, method))

        logger.setLevel(logging.INFO)

        pdus = config.get('content', 'pdus')
        for pdu in pdus.split():
            try:
                pduMap[getattr(v2c, pdu + 'PDU').tagSet] = pdu

            except AttributeError:
                raise SnmpfwdError('%s: unknown PDU %s' % (PLUGIN_NAME, pdu))

            else:
                debug('%s: PDU ACL includes %s' % (PLUGIN_NAME, pdu))

        try:
Exemple #12
0
    def trunkCbFun(trunkId, msgId, trunkReq):

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

        trunkReq['trunk-id'] = trunkId

        k = [
            str(x) for x in (trunkReq['server-snmp-engine-id'],
                             trunkReq['server-snmp-transport-domain'],
                             trunkReq['server-snmp-peer-address'] + ':' +
                             str(trunkReq['server-snmp-peer-port']),
                             trunkReq['server-snmp-bind-address'] + ':' +
                             str(trunkReq['server-snmp-bind-port']),
                             trunkReq['server-snmp-security-model'],
                             trunkReq['server-snmp-security-level'],
                             trunkReq['server-snmp-security-name'],
                             trunkReq['server-snmp-context-engine-id'],
                             trunkReq['server-snmp-context-name'])
        ]

        k.append(snmpPduTypesMap.get(trunkReq['server-snmp-pdu'].tagSet, '?'))
        k.append('|'.join([
            str(x[0])
            for x in v2c.apiPDU.getVarBinds(trunkReq['server-snmp-pdu'])
        ]))
        k = '#'.join(k)

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

        k = [
            str(x) for x in (trunkReq['server-snmp-credentials-id'],
                             trunkReq['server-snmp-context-id'],
                             trunkReq['server-snmp-content-id'],
                             trunkReq['server-snmp-peer-id'])
        ]
        k = '#'.join(k)

        for x, y in srvClassIdList:
            if y.match(k):
                srvClassId = trunkReq[
                    'server-classification-id'] = macro.expandMacro(
                        x, trunkReq)
                break
        else:
            srvClassId = None

        logCtx = LogString(trunkReq)

        errorIndication = None

        peerIdList = routingMap.get(
            (origPeerId, srvClassId, macro.expandMacro(trunkId, trunkReq)))
        if not peerIdList:
            log.error('unroutable trunk message #%s' % msgId, ctx=logCtx)
            errorIndication = 'no route to SNMP peer configured'

        cbCtx = trunkId, msgId, trunkReq, (), {}

        if errorIndication:
            snmpCbFun(None, None, errorIndication, None, cbCtx)
            return

        pluginIdList = pluginIdMap.get(
            (origPeerId, srvClassId, macro.expandMacro(trunkId, trunkReq)))
        for peerId in peerIdList:
            peerId = macro.expandMacro(peerId, trunkReq)

            trunkReqCopy = trunkReq.copy()

            (snmpEngine, contextEngineId, contextName, bindAddr, bindAddrMacro,
             peerAddr, peerAddrMacro) = peerIdMap[peerId]

            if bindAddrMacro:
                bindAddr = macro.expandMacro(bindAddrMacro, trunkReqCopy), 0

            if peerAddrMacro:
                peerAddr = macro.expandMacro(peerAddrMacro, trunkReqCopy), 161

            if bindAddr and peerAddr:
                updateEndpoints(bindAddr, peerAddr)

            trunkReqCopy['snmp-peer-id'] = peerId

            trunkReqCopy['snmp-context-engine-id'] = contextEngineId
            trunkReqCopy['snmp-context-name'] = contextName

            trunkReqCopy['snmp-bind-address'], trunkReqCopy[
                'snmp-bind-port'] = bindAddr
            trunkReqCopy['snmp-peer-address'], trunkReqCopy[
                'snmp-peer-port'] = peerAddr

            logCtx.update(trunkReqCopy)

            pdu = trunkReqCopy['server-snmp-pdu']

            if pluginIdList:
                reqCtx = {}

                cbCtx = trunkId, msgId, trunkReqCopy, pluginIdList, reqCtx

                for pluginNum, pluginId in enumerate(pluginIdList):

                    if pdu.tagSet in rfc3411.notificationClassPDUs:
                        st, pdu = pluginManager.processNotificationRequest(
                            pluginId, snmpEngine, pdu, trunkReqCopy, reqCtx)

                    elif pdu.tagSet not in rfc3411.unconfirmedClassPDUs:
                        st, pdu = pluginManager.processCommandRequest(
                            pluginId, snmpEngine, pdu, trunkReqCopy, reqCtx)

                    else:
                        log.error('ignoring unsupported PDU', ctx=logCtx)
                        break

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

                    elif st == status.DROP:
                        log.debug(
                            'received trunk message #%s, plugin %s muted request'
                            % (msgId, pluginId),
                            ctx=logCtx)
                        snmpCbFun(snmpEngine, None, None, None, cbCtx)
                        return

                    elif st == status.RESPOND:
                        log.debug(
                            'received trunk message #%s, plugin %s forced immediate response'
                            % (msgId, pluginId),
                            ctx=logCtx)
                        snmpCbFun(snmpEngine, None, None, pdu, cbCtx)
                        return

            snmpMessageSent = False

            if pdu.tagSet in rfc3411.notificationClassPDUs:
                if pdu.tagSet in rfc3411.unconfirmedClassPDUs:
                    try:
                        notificationOriginator.sendPdu(
                            snmpEngine, peerId,
                            macro.expandMacro(contextEngineId, trunkReq),
                            macro.expandMacro(contextName, trunkReq), pdu)

                        snmpMessageSent = True

                    except PySnmpError:
                        errorIndication = 'failure sending SNMP notification'
                        log.error('trunk message #%s, SNMP error: %s' %
                                  (msgId, sys.exc_info()[1]),
                                  ctx=logCtx)

                    else:
                        errorIndication = None

                    # respond to trunk right away
                    snmpCbFun(snmpEngine, None, errorIndication, None, cbCtx)

                else:
                    try:
                        notificationOriginator.sendPdu(
                            snmpEngine, peerId,
                            macro.expandMacro(contextEngineId, trunkReq),
                            macro.expandMacro(contextName, trunkReq), pdu,
                            snmpCbFun, cbCtx)

                        snmpMessageSent = True

                    except PySnmpError:
                        log.error('trunk message #%s, SNMP error: %s' %
                                  (msgId, sys.exc_info()[1]),
                                  ctx=logCtx)

            elif pdu.tagSet not in rfc3411.unconfirmedClassPDUs:
                try:
                    commandGenerator.sendPdu(
                        snmpEngine, peerId,
                        macro.expandMacro(contextEngineId, trunkReq),
                        macro.expandMacro(contextName, trunkReq), pdu,
                        snmpCbFun, cbCtx)

                    snmpMessageSent = True

                except PySnmpError:
                    errorIndication = 'failure sending SNMP command'
                    log.error('trunk message #%s, SNMP error: %s' %
                              (msgId, sys.exc_info()[1]),
                              ctx=logCtx)

                    # respond to trunk right away
                    snmpCbFun(snmpEngine, None, errorIndication, None, cbCtx)

            else:
                log.error('ignoring unsupported PDU', ctx=logCtx)

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