Hi all,
I'm working on an snmp application, written in C, that requests
information from many devices (I'm working with many "H3C S3600"
switches and some debian hosts).
You can find a simple extract of program with some test cases attached.
When I run the program, some requests working, others gone inexplicably
in timeout. (All configuration are equals and all hosts are up)
I tried with "normal" APIs and "threaded" APIs with this configurations:
Sequential requests in "for cycle":
* v2 - 1 host - multiple request(20000 retries)=> OK
* v2 - multiple host - single/multiple request => OK
* v3 - 1 host - multiple request (20000 retries)=> OK
* *v3* - *multiple host* - single/multiple request => *FAIL*
Sequential requests in single program, one *fork* for request OR one
*fork+exec* for request:
* v2 - 1 host - multiple request (20000 retries)=> OK
* v2 - multiple host - single/multiple request => OK
* v3 - 1 host - multiple request (20000 retries)=> OK
* v3 - multiple host - single/multiple request => *OK*
Here an example of output: (use ./test -h for usage)
$ ./test -r20 -t wrapper-v2 192.168.0.{2,4,5,6,7}
== Run 19 ==
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (2530553) 7:01:45.53
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (2530573) 7:01:45.73
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (2530567) 7:01:45.67
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (2530516) 7:01:45.16
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (2530591) 7:01:45.91
... etc. etc. ...
== Run 0 ==
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (2530622) 7:01:46.22
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (2530641) 7:01:46.41
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (2530635) 7:01:46.35
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (2530584) 7:01:45.84
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (2530658) 7:01:46.58
$ ./test -r1 -t wrapper *-v3* 192.168.0.{2,4,5,6,7}
== Run 0 ==
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (2110922) 5:51:49.22
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (2110947) 5:51:49.47
*Timeout*: No response from 192.168.0.5. <= *FAIL*
*Timeout*: No response from 192.168.0.6.<= *FAIL*
*Timeout*: No response from 192.168.0.7.<= *FAIL*
$ ./test -r2 -t thread -v2 192.168.0.{2,4,5,6,7}
== Run 1 ==
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (2795135) 7:45:51.35
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (2795154) 7:45:51.54
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (2795149) 7:45:51.49
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (2795095) 7:45:50.95
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (2795171) 7:45:51.71
== Run 0 ==
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (2795138) 7:45:51.38
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (2795157) 7:45:51.57
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (2795152) 7:45:51.52
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (2795098) 7:45:50.98
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (2795174) 7:45:51.74
$ ./test -r2 -t thread *-v3* 192.168.0.{2,4,5,6,7}
== Run 1 ==
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (2795664) 7:45:56.64
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (2795688) 7:45:56.88
192.168.0.5: SNMP write error: Timeout.<= *FAIL*
192.168.0.6: SNMP write error: Timeout.<= *FAIL*
192.168.0.7: SNMP write error: Timeout.<= *FAIL*
== Run 0 ==
192.168.0.2: SNMP write error: Timeout.
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (2798112) 7:46:21.12
192.168.0.5: SNMP write error: Timeout.<= *FAIL*
192.168.0.6: SNMP write error: Timeout.<= *FAIL*
192.168.0.7: SNMP write error: Timeout.<= *FAIL*
I really appreciate any help on this issue.
Best regards
Marco Bascetta
--
Marco Bascetta - Sadel SpA
Software Development
Via Serenari 9, Castel Maggiore (BO)
Tel. 051 705884 Int. 2501
CC = gcc
CFLAGS = -I. `net-snmp-config --cflags` -g -ggdb -Wall
BUILDLIBS = `net-snmp-config --libs`
all: test
#Compile all
.c.o:
gcc -c $(CFLAGS) -o $@ $<
#Compile test
test: clean my_api.o
$(CC) $(CFLAGS) -o test test.c $(BUILDLIBS) my_api.o
$(CC) $(CFLAGS) -o test_api test_api.c $(BUILDLIBS) my_api.o
#Clean rules
.PHONY clean:
rm -f test test_api *.o core
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/time.h>
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include "my_api.h"
#define MY_USER "my_username"
#define MY_PASS "my_password"
static void deinitSession(netsnmp_session *session);
static void deinitSession_v3(netsnmp_session *session);
static void initSession(netsnmp_session *session,const char *address);
static void initSession_v3(netsnmp_session *session);
static void initSession_v2c(netsnmp_session *session);
static char* sUpTime = "1.3.6.1.2.1.1.3.0" ;
static oid oUpTime[] = { 1,3,6,1,2,1,1,3,0 };
static int input_version = 0;
int request(const char *address, int type, int version) {
int iRetVal = -1;
input_version = version;
SOCK_STARTUP;
switch( type ) {
case D_WRAPPER:
iRetVal = request_wrapper(address);
break;
case D_API:
iRetVal = request_api(address);
break;
case D_THREAD:
iRetVal = request_thread(address);
break;
default:
break;
}
SOCK_CLEANUP;
return iRetVal;
}
int request_wrapper( const char *address) {
int iRetVal = 0;
//netsnmp_session session, *ss;
netsnmp_session *ss;
netsnmp_session *session = (netsnmp_session*)malloc(sizeof(netsnmp_session));
netsnmp_variable_list *vars = NULL;
// Initialize the SNMP library
init_snmp(address);
// Initialize a "session" that defines who we're going to talk to
memset(session,0,sizeof(netsnmp_session));
snmp_sess_init( session ); // set up defaults
initSession(session,address);
// Open the session
if( (ss = snmp_open( session )) != NULL) {
if( ( snmp_varlist_add_variable( &vars , oUpTime, OID_LENGTH(oUpTime), ASN_NULL, NULL, 0)) != NULL ) {
if( netsnmp_query_get( vars, ss ) == SNMP_ERR_NOERROR ) {
netsnmp_variable_list *curVar;
for( curVar = vars; curVar; curVar = curVar->next_variable ) {
print_variable( curVar->name, curVar->name_length, curVar );
}
} else {
snmp_sess_perror( address, ss );
iRetVal = -1;
}
snmp_free_varbind(vars);
} else {
fprintf(stderr,"[%s:%d] Unable to add Variable\n",__FUNCTION__,__LINE__);
}
} else {
snmp_sess_perror( "ack", session );
iRetVal = 1;
}
deinitSession(session);
return iRetVal;
}
int request_api( const char *address ) {
int status, iRetVal = 0;
netsnmp_session session, *ss;
netsnmp_pdu *pdu = NULL,
*response = NULL;
netsnmp_variable_list *vars;
oid anOID[MAX_OID_LEN];
size_t anOID_len;
// Initialize the SNMP library
init_snmp(address);
// Initialize a "session" that defines who we're going to talk to
snmp_sess_init(&session); // set up defaults
initSession(&session,address);
// Open the session
ss = snmp_open( &session ); // establish the session
if (!ss) {
snmp_perror("snmp_open");
return -1;
}
// Create the PDU for the data for our request.
// 1) We're going to GET the system.sysDescr.0 node.
pdu = snmp_pdu_create( SNMP_MSG_GET );
anOID_len = MAX_OID_LEN;
if (!snmp_parse_oid( sUpTime, anOID, &anOID_len )) {
snmp_perror( sUpTime );
return -1;
}
snmp_add_null_var( pdu, anOID, anOID_len );
// Send the Request out.
status = snmp_synch_response( ss, pdu, &response );
// Process the response.
if( status==STAT_SUCCESS && response->errstat==SNMP_ERR_NOERROR ) {
// SUCCESS: Print the result variables
for( vars = response->variables; vars; vars = vars->next_variable ) {
print_variable( vars->name, vars->name_length, vars );
}
} else {
// FAILURE: print what went wrong!
if( status == STAT_SUCCESS )
fprintf( stderr, "Error in packet\nReason: %s\n", snmp_errstring( response->errstat ) );
else if( status == STAT_TIMEOUT )
fprintf( stderr, "Timeout: No response from %s.\n", session.peername );
else
snmp_perror( address );
iRetVal = -1;
}
// Clean up:
// 1) free the response.
// 2) close the session.
if (response)
snmp_free_pdu( response );
snmp_close( ss );
deinitSession(&session);
// free(session.peername);
// snmp_shutdown(address); //TRY...
return iRetVal;
}
int request_thread( const char *address ) {
int status, iRetVal = 0;
int liberr, syserr;
char *errstr;
void *sessp; /* <-- an opaque pointer, not a struct pointer */
struct snmp_session session, *sptr;
netsnmp_pdu *pdu = NULL,
*response = NULL;
netsnmp_variable_list *vars;
oid anOID[MAX_OID_LEN];
size_t anOID_len;
// Initialize the SNMP library
init_snmp(address);
// Initialize a "session" that defines who we're going to talk to
snmp_sess_init(&session); // set up defaults
initSession(&session,address);
// Open the session
sessp = snmp_sess_open( &session );
if (sessp==NULL) {
/* Error codes found in open calling argument */
snmp_error( &session, &liberr, &syserr, &errstr );
printf("SNMP create error %s.\n", errstr );
free( errstr );
return -1;
}
sptr = snmp_sess_session( sessp ); /* <-- get the snmp_session pointer */
// Create the PDU for the data for our request.
// 1) We're going to GET the system.sysDescr.0 node.
pdu = snmp_pdu_create( SNMP_MSG_GET );
anOID_len = MAX_OID_LEN;
if (!snmp_parse_oid( sUpTime, anOID, &anOID_len )) {
snmp_sess_perror( sUpTime,sptr );
return -1;
}
snmp_add_null_var( pdu, anOID, anOID_len );
// /* Pass sptr to snmp_sess_error from here forward */
// /* Change the community name */
// free(sptr->community);
// sptr->community = (u_char*)strdup( "public" );
// sptr->community_len = strlen( "public" );
status = snmp_sess_synch_response(sessp, pdu,&response);
if( status==STAT_SUCCESS && response->errstat==SNMP_ERR_NOERROR ) {
// SUCCESS: Print the result variables
for( vars = response->variables; vars; vars = vars->next_variable ) {
print_variable( vars->name, vars->name_length, vars );
}
} else {
snmp_sess_error(sessp, &liberr, &syserr, &errstr);
fprintf(stderr,"%s: SNMP write error: %s.\n",address,errstr);
free(errstr);
iRetVal = -1;
}
// Clean up:
// 1) free the response.
// 2) close the session.
if (response)
snmp_free_pdu( response );
snmp_sess_close( sessp );
deinitSession(&session);
return iRetVal;
}
static void deinitSession(netsnmp_session *session) {
free(session->peername);
if( input_version == 3 )
deinitSession_v3(session);
}
static void deinitSession_v3(netsnmp_session *session) {
free(session->securityName);
}
static void initSession(netsnmp_session *session,const char *address) {
session->peername = strdup(address);
if( input_version == 3 ) {
initSession_v3(session);
} else if( input_version == 2 ) {
initSession_v2c(session);
} else {
fprintf(stderr,"version urecognized: %d\n",input_version);
}
}
static void initSession_v2c(netsnmp_session *session) {
// set the SNMP version number
session->version=SNMP_VERSION_2c;
session->community = (u_char*)"public";
session->community_len = strlen((char*)session->community);
}
static void initSession_v3(netsnmp_session *session) {
// set the SNMP version number
session->version=SNMP_VERSION_3;
// set the SNMPv3 user name
session->securityName = strdup(MY_USER);
session->securityNameLen = strlen(session->securityName);
// set the security level to authenticated, but not encrypted
session->securityLevel = SNMP_SEC_LEVEL_AUTHPRIV;
// set the authentication method to SHA1
session->securityAuthProto = usmHMACSHA1AuthProtocol;
session->securityAuthProtoLen = USM_AUTH_PROTO_SHA_LEN;
session->securityAuthKeyLen = USM_AUTH_KU_LEN;
// set the privacy method to AES
session->securityPrivProto = usmAESPrivProtocol;
session->securityPrivProtoLen = USM_PRIV_PROTO_AES_LEN;
session->securityPrivKeyLen = USM_PRIV_KU_LEN;
// set the authentication key to a SHA1 hashed version of our passphrase
if (generate_Ku(session->securityAuthProto, session->securityAuthProtoLen,
(u_char *) MY_PASS, strlen(MY_PASS),
session->securityAuthKey, &session->securityAuthKeyLen) != SNMPERR_SUCCESS) {
snmp_perror("test_ authentication");
// snmp_log(LOG_ERR, "Error generating Ku from authentication pass phrase. \n");
exit(1);
}
// set the privacy key to a AES hashed version of our passphrase
if (generate_Ku(session->securityAuthProto, session->securityAuthProtoLen,
(u_char *) MY_PASS, strlen(MY_PASS),
session->securityPrivKey, &session->securityPrivKeyLen) != SNMPERR_SUCCESS) {
snmp_perror("test_ privacy");
// snmp_log(LOG_ERR, "Error generating Ku from privacy pass phrase. \n");
exit(1);
}
}
#ifndef __TEST_API_H__
#define __TEST_API_H__
#define D_NULL 0
#define D_API 1
#define D_WRAPPER 2
#define D_THREAD 3
int request(const char *address, int type, int version);
int request_wrapper(const char *address);
int request_api(const char *address);
int request_thread(const char *address);
#endif
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <getopt.h>
#include "my_api.h"
//extern char **environ;
static void usage( char *program );
static void parseOptions( int argc, char **argv );
static void checkOptions( int argc, char *program );
static void exit_check_fail( char *program, char opt );
static char *input_version_str = NULL;
static int input_version = 0;
static char *input_type_str = NULL;
static int input_type = 0;
static int input_repeat = 0;
static int verboseMode = 0;
static int execMode = 0;
static int forkMode = 0;
int main( int argc, char *argv[] ) {
int iRetVal = 0;
parseOptions( argc, argv );
checkOptions( argc, argv[0] );
while( input_repeat-- ) {
int idx = optind;
printf( "== Run %d ==\n", input_repeat );
for( ; idx<argc; idx++ ) {
if( execMode || forkMode ) {
int pid = fork();
if( pid < 0 ) {
fprintf(stderr,"CAZZO, unable to fork\n");
} else if( pid == 0 ) { //SON
printf(" Host[%d]: %s === ", getpid(), argv[idx] ); fflush(stdout);
if( execMode ) {
execl("./test_api","test_api","-v",input_version_str,"-t",input_type_str,argv[idx],NULL);
} else {
request(argv[idx],input_type,input_version);
}
return 0;
} else { //padre
int status;
wait(&status);
}
} else {
request(argv[idx],input_type,input_version);
}
}
}
return iRetVal;
}
static void parseOptions( int argc, char **argv ) {
int opt;
int longindex;
static struct option long_options[] = {
{ "exec" , 0, 0, 'e' },
{ "fork" , 0, 0, 'f' },
{ "help" , 0, 0, 'h' },
{ "repeat" , 1, 0, 'r' },
{ "type" , 1, 0, 't' },
{ "version", 1, 0, 'v' },
{ "verbose", 0, 0, 'V' },
{ 0, 0, 0, 0 }
};
while( ( opt = getopt_long( argc, argv, "efhr:t:v:V", long_options, &longindex ) ) !=-1 ) {
switch( opt ) {
case 'e':
execMode = 1;
break;
case 'f':
forkMode = 1;
break;
case 'r':
input_repeat = atoi( optarg );
break;
case 't':
input_type_str = optarg;
if( strcmp("api", optarg) == 0 ) {
input_type = D_API;
} else if( strcmp("thread", optarg) == 0 ) {
input_type = D_THREAD;
} else if( strcmp("wrapper", optarg) == 0 ) {
input_type = D_WRAPPER;
} else {
input_type = D_NULL;
input_type_str = NULL;
}
break;
case 'v':
input_version = atoi( optarg );
input_version_str = optarg;
break;
case 'V':
verboseMode = 1;
break;
case 'h':
default:
usage( argv[0] );
exit( 0 );
}
}
}
static void checkOptions( int argc, char *program ) {
if(input_repeat<1) {
exit_check_fail( program, 'r' );
}
if( input_version != 2 && input_version != 3 ) {
exit_check_fail( program, 'v' );
}
if( input_type == D_NULL ) {
exit_check_fail( program, 't' );
}
if( forkMode && execMode ) {
fprintf( stderr, "Could not use -f and -e flags together.\n" );
usage( program );
exit( -1 );
}
if (optind==argc) {
fprintf( stderr, "No hostname specified.\n" );
usage( program );
exit( -1 );
}
}
static void exit_check_fail( char *program, char opt ) {
fprintf( stderr,
"Option -%c omitted or wrong value\n", opt );
usage( program );
exit( -1 );
}
static void usage( char *program ) {
printf( "usage: %s <options> hostname...\n", program );
printf( "\t -r, --repeat <repeat_times>\n\t\t Numbers of repeat\n" );
printf( "\t -t, --type <type of API used>\n\t\t Type of api used to query hosts (api|thread|wrapper) \n" );
printf( "\t -v, --version\n\t\t Specify SNMP version (2|3)\n" );
printf( "\t -V, --verbose\n\t\t Verbose output\n" );
printf( "\t -h, --help\n\t\t Show this help\n" );
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include "my_api.h"
static void usage( char *program );
static void parseOptions( int argc, char **argv );
static void checkOptions( int argc, char *program );
static void exit_check_fail( char *program, char opt );
static int input_type = 0;
static int input_version = 0;
static int verboseMode = 0;
int main( int argc, char *argv[] ) {
int iRetVal = 0;
parseOptions( argc, argv );
checkOptions( argc, argv[0] );
request(argv[optind],input_type,input_version);
return iRetVal;
}
static void parseOptions( int argc, char **argv ) {
int opt;
int longindex;
static struct option long_options[] = {
{ "help" , 0, 0, 'h' },
{ "type" , 1, 0, 't' },
{ "version", 1, 0, 'v' },
{ "verbose", 0, 0, 'V' },
{ 0, 0, 0, 0 }
};
while( ( opt = getopt_long( argc, argv, "ht:v:V", long_options, &longindex ) ) !=-1 ) {
switch( opt ) {
case 't':
if( strcmp("api", optarg) == 0 ) {
input_type = D_API;
} else if( strcmp("thread", optarg) == 0 ) {
input_type = D_THREAD;
} else if( strcmp("wrapper", optarg) == 0 ) {
input_type = D_WRAPPER;
} else {
input_type = D_NULL;
}
break;
case 'v':
input_version = atoi( optarg );
break;
case 'V':
verboseMode = 1;
break;
case 'h':
default:
usage( argv[0] );
exit( 0 );
}
}
}
static void checkOptions( int argc, char *program ) {
if( input_version != 2 && input_version != 3 ) {
exit_check_fail( program, 'v' );
}
if( input_type == D_NULL ) {
exit_check_fail( program, 't' );
}
if (optind==argc) {
fprintf( stderr, "No hostname specified.\n" );
usage( program );
exit( -1 );
}
}
static void exit_check_fail( char *program, char opt ) {
fprintf( stderr,
"Option -%c omitted or wrong value\n", opt );
usage( program );
exit( -1 );
}
static void usage( char *program ) {
printf( "usage: %s <options> hostname...\n", program );
printf( "\t -t, --type <type of API used>\n\t\t Type of api used to query hosts (api|thread|wrapper) \n" );
printf( "\t -v, --version\n\t\t Specify SNMP version (2|3)\n" );
printf( "\t -V, --verbose\n\t\t Verbose output\n" );
printf( "\t -h, --help\n\t\t Show this help\n" );
}
------------------------------------------------------------------------------
Achieve unprecedented app performance and reliability
What every C/C++ and Fortran developer should know.
Learn how Intel has extended the reach of its next-generation tools
to help boost performance applications - inlcuding clusters.
http://p.sf.net/sfu/intel-dev2devmay
_______________________________________________
Net-snmp-coders mailing list
Net-snmp-coders@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/net-snmp-coders