Mutliple SNMPv3 Target in multithread

Hello
I’m using SNMP4j 2.8.18 to perform multi-threaded OID queries on different SNMPv3 devices, with different security name, authentication and privacy settings.

I use ScheduledExecutorService to execute the SNMPv3 OID query method as follows:

SubTreeRunnerV3 sub1 = new SubTreeRunnerV3("192.168.1.1", SecurityLevel.AUTH_PRIV, "account1", "passwd1", AuthMD5.ID, "passwd1", PrivAES128.ID, oids);
//sub2 ~ sub7 omitted

executor.scheduleAtFixedRate(sub1, 1, 10, TimeUnit.SECONDS);
executor.scheduleAtFixedRate(sub2, 2, 10, TimeUnit.SECONDS);
executor.scheduleAtFixedRate(sub3, 3, 10, TimeUnit.SECONDS);
executor.scheduleAtFixedRate(sub4, 4, 10, TimeUnit.SECONDS);
executor.scheduleAtFixedRate(sub5, 5, 10, TimeUnit.SECONDS);
executor.scheduleAtFixedRate(sub6, 6, 10, TimeUnit.SECONDS);
executor.scheduleAtFixedRate(sub7, 7, 10, TimeUnit.SECONDS);

This works fine with a 10-second execution interval. However, when I change the interval to 1 second, the OID responses fail to return successfully from all devices. Only 1 or 2 threads continue working, while the others display timeout error messages.

Here is my code for the SNMPv3 OID query:

public SubTreeRunnerV3(String host, int securityLevel, String userName, String authPwd, OID authProtocol, String privPwd, OID privProtocol, List<String> oidList) {
        this.host = host;
        this.securityLevel = securityLevel;
        this.userName = userName;
        this.authPwd = authPwd;
        this.authProtocol = authProtocol;
        this.privPwd = privPwd;
        this.privProtocol = privProtocol;
        this.oidList = oidList;
}

public void run() {
        logKey = "[" + host + "]: ";
        Thread.currentThread().setName("SNMPv3-" + host);
        
        try {
            TransportMapping transport = new DefaultUdpTransportMapping();
            transport.listen();
            Snmp snmp = new Snmp(transport);

            OctetString engineId = new OctetString(MPv3.createLocalEngineID());
            USM usm = new USM(SecurityProtocols.getInstance(), engineId, 0);
            SecurityModels.getInstance().addSecurityModel(usm);
            System.out.println(logKey + "EngineId: " + engineId.toString());

            UsmUser user = null;
            switch (securityLevel) {
                case SecurityLevel.NOAUTH_NOPRIV:
                    user = new UsmUser(new OctetString(userName),
                            null,
                            null,
                            null,
                            null);
                    break;
                case SecurityLevel.AUTH_NOPRIV:
                    user = new UsmUser(new OctetString(userName),
                            authProtocol,
                            new OctetString(authPwd),
                            null,
                            null);
                    break;
                case SecurityLevel.AUTH_PRIV:
                    user = new UsmUser(new OctetString(userName),
                            authProtocol,
                            new OctetString(authPwd),
                            privProtocol,
                            new OctetString(privPwd));
                    break;
                default :
                    System.out.println("Unkown Security level");
            }//end switch securityLevel

            // add user to the USM
            snmp.getUSM().addUser(new OctetString(userName), user);

            // create the target
            UserTarget target = new UserTarget();
            target.setAddress(GenericAddress.parse("udp:" + host + "/" + port));
            target.setRetries(retry);
            target.setTimeout(timeout);
            target.setVersion(SnmpConstants.version3);
            target.setSecurityLevel(securityLevel);
            target.setSecurityName(new OctetString(userName));

            int responseCount = 0;

            TreeUtils treeUtils = new TreeUtils(snmp, new DefaultPDUFactory(PDU.GETBULK));
            for (String oid : oidList) {
                List<TreeEvent> events = treeUtils.getSubtree(target, new OID(oid));

                if (events == null || events.size() == 0) {
                    System.out.println(logKey + "Error: oid " + oid + " no response ");
                    continue;
                }

                for (TreeEvent event : events) {
                    if (event == null || event.isError()) {
                        System.out.println(logKey + "Error: " + event.getErrorMessage());
                        continue;
                    }

                    VariableBinding[] varBindings = event.getVariableBindings();
                    if (varBindings != null) {
                        responseCount += varBindings.length;
                    }
                }
            }

            System.out.println(logKey + "Response: " + responseCount);
            
            snmp.close();
            transport.close();
        } catch (Exception e) {
            System.out.println(logKey + "Exception occour");
        }

    }

How can I ensure consistent responses from all devices when the execution interval is set to 1 second or even shorter?

You probably won’t like my answer, but buying faster devices or developing faster agents for the devices might help :wink:
On the other hand, you can try to get the information from the devices in a much more efficient way. For example, using GETBULK to get whole sub-trees is the most inefficient way in most cases.

BTW, your application will not work with SNMPv3 authentication because you do not persistently safe the engineBoots counter!
See SNMP4J 2.8.6- TCP traps coming from different ips are lost