From b9288caaf624563babf164ef1411a4d5da0f47da Mon Sep 17 00:00:00 2001 From: Shteryana Shopova Date: Tue, 10 Jan 2012 15:29:03 +0000 Subject: [PATCH] Implement an option to execute SNMP walks using GETBULK requests in bsnmpwalk(1) retrieving multiple values with a Single PDU. Reviewed by: philip@ Tested by: tsanand129 (at) gmail (dot) com --- usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.1 | 19 ++++++-- usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.c | 48 ++++++++++++------- .../bsnmpd/tools/libbsnmptools/bsnmptools.c | 17 +++++-- .../bsnmpd/tools/libbsnmptools/bsnmptools.h | 4 +- 4 files changed, 62 insertions(+), 26 deletions(-) diff --git a/usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.1 b/usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.1 index 18b7eb6d689d..950c114f79ab 100644 --- a/usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.1 +++ b/usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.1 @@ -33,7 +33,7 @@ .\" .\" $FreeBSD$ .\" -.Dd September 17, 2007 +.Dd January 10, 2012 .Dt BSNMPGET 1 .Os .Sh NAME @@ -112,7 +112,7 @@ objects whose values will be retrived, waits for a response and prints it if received successfully. .Pp .Nm Bsnmpwalk -queries an agent with SMNP GetNextRequest packets, +queries an agent with ether SMNP GetNextRequest or GetBulkRequest packets, asking for values of OID instances that are a part of the object subtree rooted at the provided OIDs. .Pp @@ -220,7 +220,7 @@ The path of the posix local (unix domain) socket if local transport is used. .It Fl M Ar max-repetitions The value for the max-repetitions field in a GetBulk PDU. -Default is 1. +Default is 10. .It Fl N Ar non-repeaters The value for the non-repeaters field in a GetBulk PDU. Default is 0. @@ -251,8 +251,17 @@ A binary localized privacy key to use when encypting/decrypting SNMPv3 PDU data. By default plain text SNMPv3 PDUs are sent. .It Fl p Ar [get|getnext|getbulk] The PDU type to send by -.Nm bsmpget . -Default is get. +.Nm bsmpget +and +.Nm bsnmpwalk . +Default is get +for +.Nm bsmpget +and getnext for +.Nm bsnmpwalk . +Getbulk allows executing the so called SNMP "bulkwalks" allowing the values of +multiple columns to be retrived in a single PDU by +.Nm bsnmpwalk . .It Fl r Ar retries Number of resends of request packets before giving up if the agent does not respond after the first try. diff --git a/usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.c b/usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.c index b3c57b7c3223..fb0c7e5e1755 100644 --- a/usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.c +++ b/usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.c @@ -76,8 +76,9 @@ usage(void) (program == BSNMPWALK) ? "[-dhnK]" : (program == BSNMPSET) ? "[-adehnK]" : "", - (program == BSNMPGET) ? " [-M max-repetitions] [-N non-repeaters]" : "", - (program == BSNMPGET) ? "[-p pdu] " : "", + (program == BSNMPGET || program == BSNMPWALK) ? + " [-M max-repetitions] [-N non-repeaters]" : "", + (program == BSNMPGET || program == BSNMPWALK) ? "[-p pdu] " : "", (program == BSNMPGET) ? " OID [OID ...]" : (program == BSNMPWALK || program == BSNMPSET) ? " [OID ...]" : "" @@ -150,7 +151,7 @@ snmptool_parse_options(struct snmp_toolinfo *snmptoolctx, int argc, char **argv) switch (program) { case BSNMPWALK: - opts = "dhnKA:b:C:I:i:l:o:P:r:s:t:U:v:"; + opts = "dhnKA:b:C:I:i:l:M:N:o:P:p:r:s:t:U:v:"; break; case BSNMPGET: opts = "aDdehnKA:b:C:I:i:l:M:N:o:P:p:r:s:t:U:v:"; @@ -398,7 +399,7 @@ snmptool_get(struct snmp_toolinfo *snmptoolctx) } if (snmp_parse_resp(&resp, &req) >= 0) { - snmp_output_resp(snmptoolctx, &resp); + snmp_output_resp(snmptoolctx, &resp, NULL); break; } @@ -460,8 +461,14 @@ snmptool_walk(struct snmp_toolinfo *snmptoolctx) struct snmp_pdu req, resp; struct asn_oid root; /* Keep the initial oid. */ int32_t outputs, rc; + uint32_t op; - snmp_pdu_create(&req, SNMP_PDU_GETNEXT); + if (GET_PDUTYPE(snmptoolctx) == SNMP_PDU_GETBULK) + op = SNMP_PDU_GETBULK; + else + op = SNMP_PDU_GETNEXT; + + snmp_pdu_create(&req, op); while ((rc = snmp_pdu_add_bindings(snmptoolctx, NULL, snmptool_add_vbind, &req, 1)) > 0) { @@ -470,6 +477,10 @@ snmptool_walk(struct snmp_toolinfo *snmptoolctx) memset(&root, 0, sizeof(struct asn_oid)); asn_append_oid(&root, &(req.bindings[0].var)); + if (op == SNMP_PDU_GETBULK) + snmpget_fix_getbulk(&req, GET_MAXREP(snmptoolctx), + GET_NONREP(snmptoolctx)); + outputs = 0; while (snmp_dialog(&req, &resp) >= 0) { if ((snmp_parse_resp(&resp, &req)) < 0) { @@ -479,21 +490,24 @@ snmptool_walk(struct snmp_toolinfo *snmptoolctx) break; } - if (!(asn_is_suboid(&root, &(resp.bindings[0].var)))) { - snmp_pdu_free(&resp); - break; - } - - if (snmp_output_resp(snmptoolctx, &resp)!= 0) { + rc = snmp_output_resp(snmptoolctx, &resp, &root); + if (rc < 0) { snmp_pdu_free(&resp); outputs = -1; break; } - outputs++; + + outputs += rc; snmp_pdu_free(&resp); - snmpwalk_nextpdu_create(SNMP_PDU_GETNEXT, - &(resp.bindings[0].var), &req); + if (rc < resp.nbindings) + break; + + snmpwalk_nextpdu_create(op, + &(resp.bindings[resp.nbindings - 1].var), &req); + if (op == SNMP_PDU_GETBULK) + snmpget_fix_getbulk(&req, GET_MAXREP(snmptoolctx), + GET_NONREP(snmptoolctx)); } /* Just in case our root was a leaf. */ @@ -503,7 +517,7 @@ snmptool_walk(struct snmp_toolinfo *snmptoolctx) if (snmp_parse_resp(&resp,&req) < 0) snmp_output_err_resp(snmptoolctx, &resp); else - snmp_output_resp(snmptoolctx, &(resp)); + snmp_output_resp(snmptoolctx, &(resp), NULL); snmp_pdu_free(&resp); } else @@ -515,7 +529,7 @@ snmptool_walk(struct snmp_toolinfo *snmptoolctx) break; } - snmp_pdu_create(&req, SNMP_PDU_GETNEXT); + snmp_pdu_create(&req, op); } if (rc == 0) @@ -1076,7 +1090,7 @@ snmptool_set(struct snmp_toolinfo *snmptoolctx) if (snmp_pdu_check(&req, &resp) > 0) { if (GET_OUTPUT(snmptoolctx) != OUTPUT_QUIET) - snmp_output_resp(snmptoolctx, &resp); + snmp_output_resp(snmptoolctx, &resp, NULL); break; } diff --git a/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c index 53deff735a0b..52aa1a9321b7 100755 --- a/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c +++ b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c @@ -132,6 +132,7 @@ snmptool_init(struct snmp_toolinfo *snmptoolctx) snmptoolctx->flags = SNMP_PDU_GET; /* XXX */ SLIST_INIT(&snmptoolctx->filelist); snmp_client_init(&snmp_client); + SET_MAXREP(snmptoolctx, SNMP_MAX_REPETITIONS); if (add_filename(snmptoolctx, bsnmpd_defs, &IsoOrgDod_OID, 0) < 0) warnx("Error adding file %s to list", bsnmpd_defs); @@ -2039,14 +2040,20 @@ snmp_output_err_resp(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu) } int32_t -snmp_output_resp(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu) +snmp_output_resp(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu, + struct asn_oid *root) { int32_t error; char p[ASN_OIDSTRLEN]; uint32_t i; struct snmp_object object; - for (i = 0, error = 0; i < pdu->nbindings; i++) { + i = error = 0; + while (i < pdu->nbindings) { + if (root != NULL && !(asn_is_suboid(root, + &(pdu->bindings[i].var)))) + break; + if (GET_OUTPUT(snmptoolctx) != OUTPUT_QUIET) { if (!ISSET_NUMERIC(snmptoolctx) && (snmp_fill_object(snmptoolctx, &object, @@ -2058,9 +2065,13 @@ snmp_output_resp(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu) } } error |= snmp_output_numval(snmptoolctx, &(pdu->bindings[i]), object.info); + i++; } - return (error); + if (error) + return (-1); + + return (i); } void diff --git a/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.h b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.h index ee28385530a4..c14fe52dd05f 100644 --- a/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.h +++ b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.h @@ -47,6 +47,8 @@ #define SNMP_DEFS_DIR "/usr/share/snmp/defs/" #define SNMP_DEFAULT_LOCAL "/var/run/snmpd.sock" +#define SNMP_MAX_REPETITIONS 10 + enum snmp_access { SNMP_ACCESS_NONE = 0, SNMP_ACCESS_GET, @@ -323,7 +325,7 @@ int32_t snmp_parse_resp(struct snmp_pdu *, struct snmp_pdu *); int32_t snmp_output_numval(struct snmp_toolinfo *, struct snmp_value *, struct snmp_oid2str *); void snmp_output_val(struct snmp_value *); -int32_t snmp_output_resp(struct snmp_toolinfo *, struct snmp_pdu *); +int32_t snmp_output_resp(struct snmp_toolinfo *, struct snmp_pdu *, struct asn_oid *); void snmp_output_err_resp(struct snmp_toolinfo *, struct snmp_pdu *); void snmp_output_engine(void); void snmp_output_keys(void);