From: Vojtech Vilimek Date: Tue, 23 Jul 2024 11:48:20 +0000 (+0200) Subject: SNMP: Minor improvements X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bdb0b7cad4c03f8963348790a87f12122150dec0;p=thirdparty%2Fbird.git SNMP: Minor improvements --- diff --git a/proto/snmp/bgp4_mib.c b/proto/snmp/bgp4_mib.c index 366f49ef4..32ec536aa 100644 --- a/proto/snmp/bgp4_mib.c +++ b/proto/snmp/bgp4_mib.c @@ -39,6 +39,7 @@ #define POPULATE_BGP4(addr, proto, conn, stats, config) populate_bgp4(c, &(addr), &(proto), &(conn), &(stats), &(config)) static inline void ip4_to_oid(struct oid *oid, ip4_addr addr); +static const STATIC_OID(2) bgp4_mib_oid = STATIC_OID_INITIALIZER(2, SNMP_MGMT, SNMP_MIB_2, SNMP_BGP4_MIB); static inline void snmp_hash_add_peer(struct snmp_proto *p, struct snmp_bgp_peer *peer) @@ -117,7 +118,7 @@ snmp_bgp_notify_common(struct snmp_proto *p, uint type, ip4_addr ip4, char last_ (void *) error_vb + snmp_varbind_size_from_len(9, AGENTX_OCTET_STRING, 2); u32 oid_ids[] = { - SNMP_MIB_2, BGP4_MIB, BGP4_MIB_PEER_TABLE, BGP4_MIB_PEER_ENTRY + SNMP_MIB_2, SNMP_BGP4_MIB, BGP4_MIB_PEER_TABLE, BGP4_MIB_PEER_ENTRY }; /* @@ -234,12 +235,12 @@ snmp_bgp_notify_backward_trans(struct snmp_proto *p, struct bgp_proto *bgp) void snmp_bgp4_register(struct snmp_proto *p) { - u32 bgp_mib_prefix[] = { SNMP_MIB_2, BGP4_MIB }; + u32 bgp_mib_prefix[] = { SNMP_MIB_2, SNMP_BGP4_MIB }; { /* Register the whole BGP4-MIB::bgp root tree node */ struct snmp_registration *reg; - reg = snmp_registration_create(p, BGP4_MIB); + reg = snmp_registration_create(p, BGP4_MIB_ID); struct oid *oid = mb_allocz(p->pool, snmp_oid_size_from_len(ARRAY_SIZE(bgp_mib_prefix))); @@ -446,9 +447,9 @@ fill_admin_status(struct mib_walk_state *walk UNUSED, struct snmp_pdu *c) return res; if (bgp_proto->p.disabled) - snmp_varbind_int(c, AGENTX_ADMIN_STOP); + snmp_varbind_int(c, BGP4_ADMIN_STOP); else - snmp_varbind_int(c, AGENTX_ADMIN_START); + snmp_varbind_int(c, BGP4_ADMIN_START); return SNMP_SEARCH_OK; } @@ -792,15 +793,9 @@ bgp4_next_peer(struct mib_walk_state *state, struct snmp_pdu *c) struct oid *oid = &c->sr_vb_start->name; /* BGP4-MIB::bgpPeerIdentifier */ - STATIC_OID(9) bgp4_peer_id = { - .n_subid = 9, - .prefix = SNMP_MGMT, - .include = 0, - .reserved = 0, - .ids = { SNMP_MIB_2, BGP4_MIB, - BGP4_MIB_PEER_TABLE, BGP4_MIB_PEER_ENTRY, BGP4_MIB_PEER_IDENTIFIER, - /* IP4_NONE */ 0, 0, 0, 0 } - }; + STATIC_OID(9) bgp4_peer_id = STATIC_OID_INITIALIZER(9, SNMP_MGMT, + /* ids */ SNMP_MIB_2, SNMP_BGP4_MIB, + BGP4_MIB_PEER_TABLE, BGP4_MIB_PEER_ENTRY, BGP4_MIB_PEER_IDENTIFIER); ip4_addr ip4 = ip4_from_oid(oid); @@ -815,12 +810,8 @@ bgp4_next_peer(struct mib_walk_state *state, struct snmp_pdu *c) int old = snmp_oid_size(oid); int new = snmp_oid_size(peer_oid); - if (new - old > 0 && (uint) new - old > c->size) - { - snmp_log("bgp4_next_peer small buffer"); - snmp_manage_tbuf(c->p, c); - oid = &c->sr_vb_start->name; // TODO fix sr_vb_start in manage_tbuf - } + if (new - old > 0 && snmp_tbuf_reserve(c, new - old)) + oid = &c->sr_vb_start->name; c->buffer += (new - old); @@ -864,7 +855,7 @@ bgp4_next_peer(struct mib_walk_state *state, struct snmp_pdu *c) } /* - * snmp_bgp_start - prepare BGP4-MIB + * snmp_bgp4_start - prepare BGP4-MIB * @p - SNMP protocol instance holding memory pool * * This function create all runtime bindings to BGP procotol structures. @@ -873,6 +864,12 @@ bgp4_next_peer(struct mib_walk_state *state, struct snmp_pdu *c) void snmp_bgp4_start(struct snmp_proto *p) { + agentx_available_mibs[BGP4_MIB_ID] = (struct oid *) &bgp4_mib_oid; + + snmp_log("snmp_bgp4_start setting bgp4_mib oid %u %p %p %p", + BGP4_MIB_ID, &agentx_available_mibs[BGP4_MIB_ID], agentx_available_mibs[BGP4_MIB_ID], &bgp4_mib_oid); + + struct snmp_config *cf = SKIP_BACK(struct snmp_config, cf, p->p.cf); /* Create binding to BGP protocols */ @@ -897,36 +894,18 @@ snmp_bgp4_start(struct snmp_proto *p) snmp_hash_add_peer(p, peer); } - const STATIC_OID(2) bgp4_mib_root = { - .n_subid = 2, - .prefix = SNMP_MGMT, - .include = 0, - .reserved = 0, - .ids = { SNMP_MIB_2, BGP4_MIB }, - }; - - const STATIC_OID(4) bgp4_mib_peer_entry = { - .n_subid = 4, - .prefix = SNMP_MGMT, - .include = 0, - .reserved = 0, - .ids = { SNMP_MIB_2, BGP4_MIB, BGP4_MIB_PEER_TABLE, BGP4_MIB_PEER_ENTRY }, - }; + const STATIC_OID(4) bgp4_mib_peer_entry = STATIC_OID_INITIALIZER(4, SNMP_MGMT, + /* ids */ SNMP_MIB_2, SNMP_BGP4_MIB, BGP4_MIB_PEER_TABLE, BGP4_MIB_PEER_ENTRY); (void) mib_tree_hint(p->pool, p->mib_tree, - (const struct oid *) &bgp4_mib_root, BGP4_MIB_IDENTIFIER); + (const struct oid *) &bgp4_mib_oid, BGP4_MIB_IDENTIFIER); (void) mib_tree_hint(p->pool, p->mib_tree, (const struct oid *) &bgp4_mib_peer_entry, BGP4_MIB_IN_UPDATE_ELAPSED_TIME); mib_node_u *node; struct mib_leaf *leaf; - STATIC_OID(3) bgp4_var = { - .n_subid = 3, - .prefix = SNMP_MGMT, - .include = 0, - .reserved = 0, - .ids = { SNMP_MIB_2, BGP4_MIB, BGP4_MIB_VERSION }, - }; + STATIC_OID(3) bgp4_var = STATIC_OID_INITIALIZER(3, SNMP_MGMT, + /* ids */ SNMP_MIB_2, SNMP_BGP4_MIB, BGP4_MIB_VERSION); struct { u32 id; @@ -966,14 +945,9 @@ snmp_bgp4_start(struct snmp_proto *p) leaf->size = leafs[i].size; } - STATIC_OID(5) bgp4_entry_var = { - .n_subid = 5, - .prefix = SNMP_MGMT, - .include = 0, - .reserved = 0, - .ids = { SNMP_MIB_2, BGP4_MIB, - BGP4_MIB_PEER_TABLE, BGP4_MIB_PEER_ENTRY, BGP4_MIB_PEER_IDENTIFIER }, - }; + STATIC_OID(5) bgp4_entry_var = STATIC_OID_INITIALIZER(5, SNMP_MGMT, + /* ids */ SNMP_MIB_2, SNMP_BGP4_MIB, + BGP4_MIB_PEER_TABLE, BGP4_MIB_PEER_ENTRY, BGP4_MIB_PEER_IDENTIFIER); struct { enum snmp_search_res (*filler)(struct mib_walk_state *state, struct snmp_pdu *c); diff --git a/proto/snmp/bgp4_mib.h b/proto/snmp/bgp4_mib.h index b77f7f34c..2639e1a2c 100644 --- a/proto/snmp/bgp4_mib.h +++ b/proto/snmp/bgp4_mib.h @@ -5,7 +5,7 @@ #include "proto/bgp/bgp.h" #include "subagent.h" -#define BGP4_MIB 15 +/* BGP4-MIB root identifier is found in snmp.h as SNMP_BGP4_MIB */ /* peers attributes */ enum bgp4_mib_peer_entry_row { @@ -26,8 +26,8 @@ enum bgp4_mib_peer_entry_row { BGP4_MIB_FSM_TRANSITIONS = 15, /* FSM established transitions */ BGP4_MIB_FSM_ESTABLISHED_TIME = 16, BGP4_MIB_RETRY_INTERVAL = 17, - BGP4_MIB_HOLD_TIME = 18, - BGP4_MIB_KEEPALIVE = 19, + BGP4_MIB_HOLD_TIME = 18, /* in read-only mode */ + BGP4_MIB_KEEPALIVE = 19, /* in read-only mode */ BGP4_MIB_HOLD_TIME_CONFIGURED = 20, BGP4_MIB_KEEPALIVE_CONFIGURED = 21, BGP4_MIB_ORIGINATION_INTERVAL = 22, /* UNSUPPORTED - 0 */ @@ -36,11 +36,18 @@ enum bgp4_mib_peer_entry_row { } PACKED; /* version of BGP, here BGP-4 */ -#define BGP4_VERSIONS ((char[]) { 0x10 }) /* OID bgp.bgpVersion */ -/* for OID bgp.bgpPeerTable.bgpPeerEntry.bgpPeerNegotiatedVersion */ +#define BGP4_VERSIONS ((char[]) { 0x10 }) /* OID BGP4-MIB::bgpVersion */ + +/* values for BGP4-MIB::bgpPeerNegotiatedVersion */ #define BGP4_MIB_NEGOTIATED_VER_VALUE 4 #define BGP4_MIB_NEGOTIATED_VER_NO_VALUE 0 +/* values for BGP4-MIB::bgpPeerAdminStatus */ +enum bgp4_admin_status { + BGP4_ADMIN_STOP = 1, + BGP4_ADMIN_START = 2, +}; + u8 snmp_bgp_get_valid(u8 state); u8 snmp_bgp_getnext_valid(u8 state); @@ -65,44 +72,6 @@ enum bgp4_mib_peer_table_rows { BGP4_MIB_PEER_ENTRY = 1, }; -enum bgp4_mib_linearized_states { - BGP4_MIB_S_INVALID = 0, /* state invalid */ - BGP4_MIB_S_START = 1, - BGP4_MIB_S_BGP, - BGP4_MIB_S_VERSION, - BGP4_MIB_S_LOCAL_AS, - BGP4_MIB_S_PEER_TABLE, - BGP4_MIB_S_PEER_ENTRY, - BGP4_MIB_S_PEER_IDENTIFIER, - BGP4_MIB_S_STATE, - BGP4_MIB_S_ADMIN_STATUS, - BGP4_MIB_S_NEGOTIATED_VERSION, - BGP4_MIB_S_LOCAL_ADDR, - BGP4_MIB_S_LOCAL_PORT, - BGP4_MIB_S_REMOTE_ADDR, - BGP4_MIB_S_REMOTE_PORT, - BGP4_MIB_S_REMOTE_AS, - BGP4_MIB_S_RX_UPDATES, - BGP4_MIB_S_TX_UPDATES, - BGP4_MIB_S_RX_MESSAGES, - BGP4_MIB_S_TX_MESSAGES, - BGP4_MIB_S_LAST_ERROR, - BGP4_MIB_S_FSM_TRANSITIONS, - BGP4_MIB_S_FSM_ESTABLISHED_TIME, - BGP4_MIB_S_RETRY_INTERVAL, - BGP4_MIB_S_HOLD_TIME, - BGP4_MIB_S_KEEPALIVE, - BGP4_MIB_S_HOLD_TIME_CONFIGURED, - BGP4_MIB_S_KEEPALIVE_CONFIGURED, - BGP4_MIB_S_ORIGINATION_INTERVAL, - BGP4_MIB_S_MIN_ROUTE_ADVERTISEMENT, - BGP4_MIB_S_IN_UPDATE_ELAPSED_TIME, - BGP4_MIB_S_PEER_TABLE_END, - BGP4_MIB_S_IDENTIFIER, /* state local identification */ - BGP4_MIB_S_END, - BGP4_MIB_S_NO_VALUE = 255, -} PACKED; - /* valid values for BGP4_MIB_STATE */ enum bgp4_mib_bgp_states { BGP4_MIB_IDLE = 1, @@ -121,7 +90,9 @@ STATIC_ASSERT(BGP4_MIB_OPENCONFIRM == BS_OPENCONFIRM + 1); STATIC_ASSERT(BGP4_MIB_ESTABLISHED == BS_ESTABLISHED + 1); /* Traps OID sub-identifiers */ -#define BGP4_MIB_ESTABLISHED_NOTIFICATION 1 -#define BGP4_MIB_BACKWARD_TRANS_NOTIFICATION 2 +enum bgp4_traps_subids { + BGP4_MIB_ESTABLISHED_NOTIFICATION = 1, + BGP4_MIB_BACKWARD_TRANS_NOTIFICATION = 2, +}; #endif diff --git a/proto/snmp/snmp.c b/proto/snmp/snmp.c index 2d81a2973..f3bf54317 100644 --- a/proto/snmp/snmp.c +++ b/proto/snmp/snmp.c @@ -123,12 +123,51 @@ #include "proto/bgp/bgp.h" const char agentx_master_addr[] = AGENTX_MASTER_ADDR; +const struct oid *agentx_available_mibs[AGENTX_MIB_COUNT + 1] = { 0 }; static void snmp_start_locked(struct object_lock *lock); static void snmp_sock_err(sock *sk, int err); static void snmp_stop_timeout(timer *tm); static void snmp_cleanup(struct snmp_proto *p); +/* + * agentx_get_mib_init - init function for agentx_get_mib() + * @p: SNMP instance protocol pool + */ +void agentx_get_mib_init(pool *p) +{ + const struct oid *src = agentx_available_mibs[AGENTX_MIB_COUNT - 1]; + size_t size = snmp_oid_size(src); + struct oid *dest = mb_alloc(p, size); + + memcpy(dest, src, size); + u8 ids = LOAD_U8(src->n_subid); + + if (ids > 0) + STORE_U32(dest->ids[ids - 1], LOAD_U32(src->ids[ids - 1]) + 1); + + agentx_available_mibs[AGENTX_MIB_COUNT] = dest; +} + +/* + * agentx_get_mib - classify an OID based on MIB prefix + * + */ +enum agentx_mibs agentx_get_mib(const struct oid *o) +{ + enum agentx_mibs mib = AGENTX_MIB_UNKNOWN; + for (uint i = 0; i < AGENTX_MIB_COUNT + 1; i++) + { + ASSERT(agentx_available_mibs[i]); + if (snmp_oid_compare(o, agentx_available_mibs[i]) < 0) + return mib; + mib = (enum agentx_mibs) i; + } + + return AGENTX_MIB_UNKNOWN; +} + + /* * snmp_rx_skip - skip all received data * @sk: communication socket @@ -517,7 +556,6 @@ snmp_start(struct proto *P) p->bgp_local_as = cf->bgp_local_as; p->bgp_local_id = cf->bgp_local_id; p->timeout = cf->timeout; - // TODO add default value for startup_delay inside bison .Y file p->startup_delay = cf->startup_delay; p->pool = p->p.pool; @@ -535,6 +573,7 @@ snmp_start(struct proto *P) mib_tree_init(p->pool, p->mib_tree); snmp_bgp4_start(p); + agentx_get_mib_init(p->pool); return snmp_set_state(p, SNMP_INIT); } diff --git a/proto/snmp/snmp.h b/proto/snmp/snmp.h index e5f126c66..2e73c3134 100644 --- a/proto/snmp/snmp.h +++ b/proto/snmp/snmp.h @@ -100,7 +100,6 @@ struct snmp_proto { struct object_lock *lock; pool *pool; /* a shortcut to the procotol mem. pool */ linpool *lp; /* linpool for bgp_trie nodes */ - slab *request_storage; /* manages storages storage for incomming requests */ enum snmp_proto_state state; @@ -140,13 +139,23 @@ struct snmp_proto { struct mib_tree *mib_tree; }; +enum agentx_mibs { + BGP4_MIB_ID, + AGENTX_MIB_COUNT, + AGENTX_MIB_UNKNOWN, +}; + +extern const struct oid *agentx_available_mibs[AGENTX_MIB_COUNT + 1]; +void agentx_get_mib_init(pool *p); +enum agentx_mibs agentx_get_mib(const struct oid *o); + struct snmp_registration; struct agentx_response; /* declared in subagent.h */ typedef void (*snmp_reg_hook_t)(struct snmp_proto *p, const struct agentx_response *res, struct snmp_registration *reg); struct snmp_registration { node n; - u8 mib_class; + enum agentx_mibs mib; u32 session_id; u32 transaction_id; u32 packet_id; @@ -155,7 +164,6 @@ struct snmp_registration { snmp_reg_hook_t reg_hook_fail; /* hook called when OID registration fail */ }; -//void snmp_tx(sock *sk); void snmp_startup(struct snmp_proto *p); void snmp_connected(sock *sk); void snmp_startup_timeout(timer *tm); diff --git a/proto/snmp/snmp_test.c b/proto/snmp/snmp_test.c index 5b5b770e7..1223d1352 100644 --- a/proto/snmp/snmp_test.c +++ b/proto/snmp/snmp_test.c @@ -401,7 +401,7 @@ t_oid_compare(void) static struct oid * snmp_oid_prefixize(struct snmp_proto *p, const struct oid *oid, struct snmp_pdu *c) { - snmp_vb_to_tx(p, oid, c); + snmp_vb_to_tx(c, oid); struct agentx_varbind *vb = c->sr_vb_start; bt_assert(vb->reserved == 0); return &vb->name; diff --git a/proto/snmp/snmp_utils.c b/proto/snmp/snmp_utils.c index e3fd96ee0..bd4263fa5 100644 --- a/proto/snmp/snmp_utils.c +++ b/proto/snmp/snmp_utils.c @@ -50,7 +50,7 @@ snmp_varbind_data(const struct agentx_varbind *vb) } struct oid * -snmp_varbind_set_name_len(struct snmp_proto *p, struct agentx_varbind **vb, u8 len, struct snmp_pdu *c) +snmp_varbind_set_name_len(struct snmp_pdu *c, struct agentx_varbind **vb, u8 len) { struct oid *oid = &(*vb)->name; @@ -64,10 +64,10 @@ snmp_varbind_set_name_len(struct snmp_proto *p, struct agentx_varbind **vb, u8 l /* We need more space */ ASSUME(len >= LOAD_U8(oid->n_subid)); uint diff_size = (len - LOAD_U8(oid->n_subid)) * sizeof(u32); - if (c->size < diff_size) + + if (snmp_tbuf_reserve(c, diff_size)) { snmp_log("varbind_set_name_len small buffer"); - snmp_manage_tbuf(p, c); oid = &(*vb)->name; } @@ -78,15 +78,12 @@ snmp_varbind_set_name_len(struct snmp_proto *p, struct agentx_varbind **vb, u8 l } void -snmp_varbind_duplicate_hdr(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_pdu *c) +snmp_varbind_duplicate_hdr(struct snmp_pdu *c, struct agentx_varbind **vb) { ASSUME(vb != NULL && *vb != NULL); uint hdr_size = snmp_varbind_header_size(*vb); - if (c->size < hdr_size) - { + if (snmp_tbuf_reserve(c, hdr_size)) snmp_log("varbind_duplicate small buffer"); - snmp_manage_tbuf(p, c); - } ASSERT(c->size >= hdr_size); byte *buffer = c->buffer; @@ -732,7 +729,7 @@ all_same: } struct snmp_registration * -snmp_registration_create(struct snmp_proto *p, u8 mib_class) +snmp_registration_create(struct snmp_proto *p, enum agentx_mibs mib) { struct snmp_registration *r; r = mb_alloc(p->p.pool, sizeof(struct snmp_registration)); @@ -743,21 +740,20 @@ snmp_registration_create(struct snmp_proto *p, u8 mib_class) /* will be incremented by snmp_session() macro during packet assembly */ r->transaction_id = p->transaction_id; r->packet_id = p->packet_id + 1; - snmp_log("using registration packet_id %u", r->packet_id); - - r->mib_class = mib_class; + r->mib = mib; + snmp_log("using registration packet_id %u", r->packet_id); add_tail(&p->registration_queue, &r->n); return r; } int -snmp_registration_match(struct snmp_registration *r, struct agentx_header *h, u8 class) +snmp_registration_match(struct snmp_registration *r, struct agentx_header *h, enum agentx_mibs mib) { snmp_log("snmp_reg_same() r->packet_id %u p->packet_id %u", r->packet_id, h->packet_id); return - (r->mib_class == class) && + (r->mib == mib) && (r->session_id == h->session_id) && (r->transaction_id == h->transaction_id) && (r->packet_id == h->packet_id); @@ -1066,7 +1062,7 @@ snmp_walk_init(struct mib_tree *tree, struct mib_walk_state *walk, const struct { mib_tree_walk_init(walk, tree); - snmp_vb_to_tx(c->p, oid, c); + snmp_vb_to_tx(c, oid); mib_node_u *node = mib_tree_find(tree, walk, &c->sr_vb_start->name); @@ -1178,11 +1174,8 @@ snmp_walk_fill(struct mib_leaf *leaf, struct mib_walk_state *walk, struct snmp_p snmp_log("walk_fill got size %u based on lt %u ls %u, calling filler()", size, leaf->type, leaf->size); - if (size >= c->size) - { - snmp_log("walk_fill small buffer size %d to %d", size, c->size); - snmp_manage_tbuf(c->p, c); - } + if (snmp_tbuf_reserve(c, size)) + snmp_log("walk_fill small buffer size"); enum snmp_search_res res = leaf->filler(walk, c); diff --git a/proto/snmp/snmp_utils.h b/proto/snmp/snmp_utils.h index c4b252e79..66fa1d379 100644 --- a/proto/snmp/snmp_utils.h +++ b/proto/snmp/snmp_utils.h @@ -54,8 +54,8 @@ uint snmp_varbind_size_unsafe(const struct agentx_varbind *vb); size_t snmp_varbind_size_from_len(uint n_subid, enum agentx_type t, uint len); int snmp_test_varbind(const struct agentx_varbind *vb); void *snmp_varbind_data(const struct agentx_varbind *vb); -struct oid *snmp_varbind_set_name_len(struct snmp_proto *p, struct agentx_varbind **vb, u8 len, struct snmp_pdu *c); -void snmp_varbind_duplicate_hdr(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_pdu *c); +struct oid *snmp_varbind_set_name_len(struct snmp_pdu *c, struct agentx_varbind **vb, u8 len); +void snmp_varbind_duplicate_hdr(struct snmp_pdu *c, struct agentx_varbind **vb); /* * AgentX - PDU headers, types, contexts @@ -98,8 +98,8 @@ byte *snmp_put_fbyte(byte *buf, u8 data); * Helpers, Misc, Debugging * */ -struct snmp_registration *snmp_registration_create(struct snmp_proto *p, u8 mib_class); -int snmp_registration_match(struct snmp_registration *r, struct agentx_header *h, u8 class); +struct snmp_registration *snmp_registration_create(struct snmp_proto *p, enum agentx_mibs mib); +int snmp_registration_match(struct snmp_registration *r, struct agentx_header *h, enum agentx_mibs mib); void snmp_dump_packet(byte *pkt, uint size); void snmp_oid_dump(const struct oid *oid); diff --git a/proto/snmp/subagent.c b/proto/snmp/subagent.c index b18c37d97..1a1adbeff 100644 --- a/proto/snmp/subagent.c +++ b/proto/snmp/subagent.c @@ -107,15 +107,17 @@ snmp_blank_header(struct agentx_header *h, enum agentx_pdu_types type) * snmp_register_ack - handle registration response * @p: SNMP protocol instance * @res: header of agentx-Response-PDU - * @class: MIB subtree associated with agentx-Register-PDU + * @mib: MIB subtree identifier */ void -snmp_register_ack(struct snmp_proto *p, struct agentx_response *res, u8 class) +snmp_register_ack(struct snmp_proto *p, struct agentx_response *res, const struct oid *oid) { + enum agentx_mibs mib = agentx_get_mib(oid); + struct snmp_registration *reg; WALK_LIST(reg, p->registration_queue) { - if (snmp_registration_match(reg, &res->h, class)) + if (snmp_registration_match(reg, &res->h, mib)) { rem_node(®->n); p->registrations_to_ack--; @@ -175,12 +177,10 @@ open_pdu(struct snmp_proto *p, struct oid *oid) #define TIMEOUT_SIZE sizeof(u32) /* 1B timeout, 3B zero padding */ /* Make sure that we have enough space in TX-buffer */ - if (c.size < AGENTX_HEADER_SIZE + TIMEOUT_SIZE + snmp_oid_size(oid) + - + snmp_str_size(cf->description)) - { + uint s = AGENTX_HEADER_SIZE + TIMEOUT_SIZE + snmp_oid_size(oid) + + snmp_str_size(cf->description); + if (snmp_tbuf_reserve(&c, s)) snmp_log("agentx-Open-PDU small buffer"); - snmp_manage_tbuf(p, &c); - } struct agentx_header *h = (void *) c.buffer; ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE); @@ -205,7 +205,7 @@ open_pdu(struct snmp_proto *p, struct oid *oid) c.buffer = snmp_put_oid(c.buffer, oid); c.buffer = snmp_put_str(c.buffer, cf->description); - uint s = update_packet_size(h, c.buffer); + s = update_packet_size(h, c.buffer); sk_send(sk, s); #undef TIMEOUT_SIZE } @@ -226,8 +226,8 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in struct snmp_pdu c; snmp_pdu_context(&c, p, sk); -#define UPTIME_SIZE sizeof(STATIC_OID(4)) -#define TRAP0_HEADER_SIZE sizeof(STATIC_OID(6)) +#define UPTIME_SIZE sizeof(STATIC_OID(4)) /* see sys_up_time_0 */ +#define TRAP0_HEADER_SIZE sizeof(STATIC_OID(6)) /* see snmp_trap_oid_0 */ uint sz = AGENTX_HEADER_SIZE + TRAP0_HEADER_SIZE + snmp_oid_size(oid) \ + size; @@ -236,11 +236,8 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in sz += UPTIME_SIZE; /* Make sure that we have enough space in TX-buffer */ - if (c.size < sz) - { + if (snmp_tbuf_reserve(&c, sz)) snmp_log("agentx-Notify-PDU small buffer"); - snmp_manage_tbuf(p, &c); - } struct agentx_header *h = (void *) c.buffer; ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE); @@ -334,11 +331,8 @@ un_register_pdu(struct snmp_proto *p, struct oid *oid, u32 bound, uint index, en uint sz = AGENTX_HEADER_SIZE + snmp_oid_size(oid) + ((bound > 1) ? BOUND_SIZE : 0); - if (c.size < sz) - { + if (snmp_tbuf_reserve(&c, sz)) snmp_log("agentx-Register-PDU small buffer"); - snmp_manage_tbuf(p, &c); - } struct agentx_header *h = (void *) c.buffer; ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE); @@ -419,11 +413,8 @@ close_pdu(struct snmp_proto *p, enum agentx_close_reasons reason) snmp_pdu_context(&c, p, sk); #define REASON_SIZE sizeof(u32) - if (c.size < AGENTX_HEADER_SIZE + REASON_SIZE) - { + if (snmp_tbuf_reserve(&c, AGENTX_HEADER_SIZE + REASON_SIZE)) snmp_log("agentx-Close-PDU small buffer"); - snmp_manage_tbuf(p, &c); - } struct agentx_header *h = (void *) c.buffer; ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE); @@ -515,11 +506,8 @@ parse_test_set_pdu(struct snmp_proto *p, byte * const pkt_start) struct snmp_pdu c; snmp_pdu_context(&c, p, sk); - if (c.size < AGENTX_HEADER_SIZE) - { + if (snmp_tbuf_reserve(&c, AGENTX_HEADER_SIZE)) snmp_log("agentx-TestSet-PDU small buffer"); - snmp_manage_tbuf(p, &c); - } res = prepare_response(p, &c); @@ -577,11 +565,8 @@ parse_sets_pdu(struct snmp_proto *p, byte * const pkt_start, enum agentx_respons struct snmp_pdu c; snmp_pdu_context(&c, p, p->sock); - if (c.size < sizeof(struct agentx_response)) - { + if (snmp_tbuf_reserve(&c, sizeof(struct agentx_response))) snmp_log("parse_sets_pdu small buffer"); - snmp_manage_tbuf(p, &c); - } struct agentx_response *r = prepare_response(p, &c); @@ -820,8 +805,8 @@ parse_response(struct snmp_proto *p, byte *res) // TODO more direct path to mib-specific code TRACE(D_PACKETS, "SNMP received agentx-Response-PDU with error %u", r->error); byte *pkt = res + sizeof(struct agentx_response); - struct oid *failed = (void *) pkt; - snmp_register_ack(p, r, snmp_get_mib_class(failed)); + struct oid *failed = (struct oid *) pkt; + snmp_register_ack(p, r, failed); break; /* @@ -867,7 +852,6 @@ do_response(struct snmp_proto *p, byte *pkt) struct agentx_response *r = (void *) pkt; struct agentx_header *h = (void *) r; - /* TODO make it asynchronous for better speed */ switch (p->state) { case SNMP_INIT: @@ -891,9 +875,8 @@ do_response(struct snmp_proto *p, byte *pkt) case SNMP_REGISTER:; pkt += AGENTX_HEADER_SIZE; - const struct oid *oid = (void *) pkt; - - snmp_register_ack(p, r, snmp_get_mib_class(oid)); + const struct oid *oid = (struct oid *) pkt; + snmp_register_ack(p, r, oid); if (p->registrations_to_ack == 0) snmp_set_state(p, SNMP_CONN); @@ -910,27 +893,6 @@ do_response(struct snmp_proto *p, byte *pkt) } } -/* - * snmp_get_mib_class - classify MIB tree belongings of OID - * @oid: OID to be classified based on prefix - */ -u8 -snmp_get_mib_class(const struct oid *oid) -{ - // TODO check code paths for oid->n_subid < 3 - if (oid->prefix != SNMP_MGMT && oid->ids[0] != SNMP_MIB_2) - return SNMP_CLASS_INVALID; - - switch (oid->ids[1]) - { - case SNMP_BGP4_MIB: - return SNMP_CLASS_BGP; - - default: - return SNMP_CLASS_END; - } -} - static inline struct oid * snmp_oid_prefixize_unsafe(struct oid *dest, const struct oid *src) { @@ -948,22 +910,18 @@ snmp_oid_prefixize_unsafe(struct oid *dest, const struct oid *src) /* * snmp_vb_to_tx - create varbind from RX buffer OID - * @p: SNMP protocol instance - * @oid: object identifier located in RX buffer * @c: PDU context + * @oid: object identifier located in RX buffer * * Create NULL initialized VarBind inside TX buffer (from @c) whose vb->name is * @oid. The @oid prefixed if possible. The result is stored in @c->sr_vb_start. */ void -snmp_vb_to_tx(struct snmp_proto *p, const struct oid *oid, struct snmp_pdu *c) +snmp_vb_to_tx(struct snmp_pdu *c, const struct oid *oid) { uint vb_hdr_size = snmp_varbind_hdr_size_from_oid(oid); - if (c->size < vb_hdr_size) - { + if (snmp_tbuf_reserve(c, vb_hdr_size)) snmp_log("SNMP vb_to_tx small buffer"); - snmp_manage_tbuf(p, c); - } ASSERT(c->size >= vb_hdr_size); struct agentx_varbind *vb = (void *) c->buffer; @@ -1017,7 +975,6 @@ response_err_ind(struct snmp_proto *p, struct agentx_response *res, enum agentx_ { STORE_U32(res->error, (u16) err); // TODO deal with auto-incrementing of snmp_pdu context c.ind - // FIXME for packets with errors reset reset payload size to null (by move c.buffer appropriately) if (err != AGENTX_RES_NO_ERROR && err != AGENTX_RES_GEN_ERROR) { TRACE(D_PACKETS, "Last PDU resulted in error %u", err); @@ -1053,6 +1010,8 @@ parse_gets_error(struct snmp_proto *p, struct snmp_pdu *c, uint len) /* * AgentX GetPDU, GetNextPDU and GetBulkPDU */ + +/* agentx-Get-PDU */ void snmp_get_pdu(struct snmp_proto *p, struct snmp_pdu *c, const struct oid *o_start, struct mib_walk_state *walk) { @@ -1072,6 +1031,7 @@ snmp_get_pdu(struct snmp_proto *p, struct snmp_pdu *c, const struct oid *o_start snmp_set_varbind_type(c->sr_vb_start, snmp_search_res_to_type(res)); } +/* agentx-GetNext-PDU */ int snmp_get_next_pdu(struct snmp_proto *p, struct snmp_pdu *c, const struct oid *o_start, struct mib_walk_state *walk) { @@ -1087,6 +1047,7 @@ snmp_get_next_pdu(struct snmp_proto *p, struct snmp_pdu *c, const struct oid *o_ return res == SNMP_SEARCH_OK; } +/* agentx-GetBulk-PDU */ void snmp_get_bulk_pdu(struct snmp_proto *p, struct snmp_pdu *c, const struct oid *o_start, struct mib_walk_state *walk, struct agentx_bulk_state *bulk) { @@ -1191,7 +1152,6 @@ parse_gets_pdu(struct snmp_proto *p, byte * const pkt_start) struct agentx_getbulk *bulk_info = (void *) pkt; ADVANCE(pkt, pkt_size, sizeof(struct agentx_getbulk)); - //TODO: bulk_state = AGENTX_BULK_STATE_INITIALIZER(bulk_info); bulk_state = (struct agentx_bulk_state) { .getbulk = { .non_repeaters = LOAD_U32(bulk_info->non_repeaters), @@ -1247,6 +1207,7 @@ parse_gets_pdu(struct snmp_proto *p, byte * const pkt_start) if (h->type == AGENTX_GET_BULK_PDU) { + // TODO: an error for now } /* We update the error, index pair on the beginning of the packet. */ @@ -1404,55 +1365,32 @@ snmp_search_check_end_oid(const struct oid *found, const struct oid *bound) } /* - * snmp_manage_tbuf - TODO - */ -void -snmp_manage_tbuf(struct snmp_proto *p, struct snmp_pdu *c) -{ - sock *sk = p->sock; - int diff; - if (c->sr_vb_start != NULL) - diff = (void *) c->sr_vb_start - (void *) sk->tbuf; - - snmp_log("snmp_manage_tbuf2()"); - sk_set_tbsize(sk, sk->tbsize + 2048); - c->size += 2048; - - if (c->sr_vb_start != NULL) - c->sr_vb_start = (struct agentx_varbind *) (sk->tbuf + diff); -} - -/* - * snmp_manage_tbuf2 - handle situation with too short transmit buffer - * @p: SNMP protocol instance - * @c: transmit packet context to use + * snmp_tbuf_reserve - TODO * - * Important note: After managing insufficient buffer size all in buffer pointers - * are invalidated! */ -void -snmp_manage_tbuf2(struct snmp_proto *p, void **ptr, struct snmp_pdu *c) +int +snmp_tbuf_reserve(struct snmp_pdu *c, size_t size) { - sock *sk = p->sock; - int diff; - if (ptr) - diff = *ptr - (void *) sk->tbuf; + if (size >= c->size) + { + struct snmp_proto *p = c->p; + sock *sk = p->sock; - snmp_log("snmp_manage_tbuf()"); - sk_set_tbsize(sk, sk->tbsize + 2048); - c->size += 2048; + int diff; + if (c->sr_vb_start != NULL) + diff = (char *) c->sr_vb_start - (char *) sk->tbuf; - if (ptr) - *ptr = sk->tbuf + diff; -} + snmp_log("snmp_tbuf_reserve()"); + sk_set_tbsize(sk, sk->tbsize + 2048); + c->size += 2048; -void -snmp_tbuf_reserve(struct snmp_pdu *c, size_t size) -{ - if (size > c->size) - { - snmp_manage_tbuf(c->p, c); + if (c->sr_vb_start != NULL) + c->sr_vb_start = (struct agentx_varbind *) (sk->tbuf + diff); + + return 1; } + + return 0; } /* diff --git a/proto/snmp/subagent.h b/proto/snmp/subagent.h index 6696d98c4..234b137a3 100644 --- a/proto/snmp/subagent.h +++ b/proto/snmp/subagent.h @@ -4,6 +4,7 @@ #include "nest/bird.h" #include "snmp.h" +#include "lib/macro.h" void snmp_start_subagent(struct snmp_proto *p); void snmp_stop_subagent(struct snmp_proto *p); @@ -43,13 +44,6 @@ extern const u32 snmp_internet[4]; #define SNMP_DEFAULT_CONTEXT 0 -enum SNMP_CLASSES { - SNMP_CLASS_INVALID = 0, - SNMP_CLASS_BGP = 1, - SNMP_CLASS_OSPF, - SNMP_CLASS_END, -}; - enum agentx_type { AGENTX_INTEGER = 2, AGENTX_OCTET_STRING = 4, @@ -75,8 +69,6 @@ enum snmp_search_res { SNMP_SEARCH_END_OF_VIEW = 3, }; -#define AGENTX_ADMIN_STOP 1 -#define AGENTX_ADMIN_START 2 #define AGENTX_PRIORITY 127 @@ -116,12 +108,17 @@ enum agentx_flags { #define SNMP_ORDER 0 #endif +/* We recommend using STORE_U32 over VALUE_U32 when possible */ #ifdef SNMP_NATIVE -#define STORE_U32(dest, val) ((dest) = (u32) (val)) -#define STORE_U16(dest, val) ((dest) = (u16) (val)) -#define STORE_U8(dest, val) ((dest) = (u8) (val)) +#define STORE_U32(dest, val) ((u32) ((dest) = (u32) (val))) +#define STORE_U16(dest, val) ((u16) ((dest) = (u16) (val))) +#define STORE_U8(dest, val) ((u8) ((dest) = (u8) (val))) #define STORE_PTR(ptr, val) (*((u32 *) (ptr)) = (u32) (val)) +#define VALUE_U32(val) ((u32) (val)) +#define VALUE_U16(val) ((u16) (val)) +#define VALUE_U8(val) ((u8) (val)) + #define LOAD_U32(src) *((u32 *) &(src)) #define LOAD_U16(src) *((u16 *) &(src)) #define LOAD_U8(src) *((u8 *) &(src)) @@ -134,6 +131,11 @@ enum agentx_flags { #define STORE_U8(dest, val) put_u8(&(dest), (val)) #define STORE_PTR(ptr, val) put_u32(ptr, val) +#define VALUE_U32(val) htonl(val) +#define VALUE_U16(val) htons(val) +#define VALUE_U8(val) ((u8) (val)) + + #define LOAD_U32(src) get_u32(&(src)) #define LOAD_U16(src) get_u16(&(src)) #define LOAD_U8(src) get_u8(&(src)) @@ -192,6 +194,16 @@ struct oid { u32 ids[sbids]; \ } +#define VALUE_U32_HELPER(x) VALUE_U32(x), +#define STATIC_OID_INITIALIZER(sbids, pref, ...) \ + { \ + .n_subid = VALUE_U8(sbids), \ + .prefix = VALUE_U8(pref), \ + .include = VALUE_U8(0), \ + .reserved = VALUE_U8(0), \ + .ids = { MACRO_FOREACH(VALUE_U32_HELPER, __VA_ARGS__) }, \ + } + /* enforced by MIB tree, see mib_tree.h for more info */ #define OID_MAX_LEN 32 @@ -319,7 +331,8 @@ enum agentx_response_errs { /* SNMP PDU info */ struct snmp_pdu { struct snmp_proto *p; - /* TX buffer */ + + /* TX buffer */ byte *buffer; /* pointer to buffer */ uint size; /* unused space in buffer */ @@ -348,9 +361,9 @@ void snmp_register(struct snmp_proto *p, struct oid *oid, uint index, uint len, void snmp_unregister(struct snmp_proto *p, struct oid *oid, uint index, uint len, uint contid); void snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, int include_uptime); -void snmp_manage_tbuf(struct snmp_proto *p, struct snmp_pdu *c); +int snmp_tbuf_reserve(struct snmp_pdu *c, size_t bytes); -void snmp_vb_to_tx(struct snmp_proto *p, const struct oid *oid, struct snmp_pdu *c); +void snmp_vb_to_tx(struct snmp_pdu *c, const struct oid *oid); u8 snmp_get_mib_class(const struct oid *oid); void snmp_register_mibs(struct snmp_proto *p); @@ -358,7 +371,6 @@ void snmp_register_mibs(struct snmp_proto *p); /* MIB modules */ void snmp_bgp4_start(struct snmp_proto *p); - #if 1 #define snmp_log(...) log(L_INFO "SNMP " __VA_ARGS__) #else