From af9a2d4cd77c011773f23758df2ab3254e27f261 Mon Sep 17 00:00:00 2001 From: Vojtech Vilimek Date: Fri, 24 May 2024 15:20:30 +0200 Subject: [PATCH] SNMP: Slow integraion of MIB tree in SNMP code --- proto/snmp/Doc | 2 +- proto/snmp/Makefile | 2 +- proto/snmp/{bgp_mib.c => bgp4_mib.c} | 722 ++++++++++++++++++++++++--- proto/snmp/{bgp_mib.h => bgp4_mib.h} | 31 +- proto/snmp/config.Y | 2 +- proto/snmp/mib_tree.c | 2 +- proto/snmp/mib_tree.h | 3 + proto/snmp/snmp.c | 11 +- proto/snmp/snmp.h | 38 +- proto/snmp/snmp_test.c | 18 +- proto/snmp/snmp_utils.c | 69 ++- proto/snmp/snmp_utils.h | 14 +- proto/snmp/subagent.c | 223 ++++++--- proto/snmp/subagent.h | 33 +- 14 files changed, 937 insertions(+), 233 deletions(-) rename proto/snmp/{bgp_mib.c => bgp4_mib.c} (62%) rename proto/snmp/{bgp_mib.h => bgp4_mib.h} (89%) diff --git a/proto/snmp/Doc b/proto/snmp/Doc index 7d2ec70b6..b1475b8a3 100644 --- a/proto/snmp/Doc +++ b/proto/snmp/Doc @@ -1,4 +1,4 @@ S snmp.c S subagent.c S snmp_utils.c -S bgp_mib.c +S bgp4_mib.c diff --git a/proto/snmp/Makefile b/proto/snmp/Makefile index 637815aff..038c85c91 100644 --- a/proto/snmp/Makefile +++ b/proto/snmp/Makefile @@ -1,4 +1,4 @@ -src := snmp.c snmp_utils.c subagent.c bgp_mib.c mib_tree.c +src := snmp.c snmp_utils.c subagent.c bgp4_mib.c mib_tree.c obj := $(src-o-files) $(all-daemon) $(cf-local) diff --git a/proto/snmp/bgp_mib.c b/proto/snmp/bgp4_mib.c similarity index 62% rename from proto/snmp/bgp_mib.c rename to proto/snmp/bgp4_mib.c index 7559042aa..b3ac160e5 100644 --- a/proto/snmp/bgp_mib.c +++ b/proto/snmp/bgp4_mib.c @@ -8,10 +8,12 @@ * Can be freely distributed and used under the terms of the GNU GPL. */ +/* need to be first header file included */ +#include "bgp4_mib.h" + #include "snmp.h" #include "snmp_utils.h" #include "subagent.h" -#include "bgp_mib.h" /* hash table macros */ #define SNMP_HASH_KEY(n) n->peer_ip @@ -25,13 +27,21 @@ /* hash table only store ip4 addresses */ #define SNMP_HASH_LESS(ip1, ip2) SNMP_HASH_LESS4(ip1,ip2) +// TODO delete me +#define SNMP_MANAGE_TBUF(...) (void)0 -/* Simply discard type */ -#define SNMP_MANAGE_TBUF(p, vb, c) snmp_manage_tbuf(p, (void **) vb, c) +#define DECLARE_BGP4(addr, proto, conn, stats, config) \ + ip4_addr addr; \ + const struct bgp_proto *proto; \ + const struct bgp_conn *conn; \ + const struct bgp_stats *stats; \ + const struct bgp_config *config -static inline void ip4_to_oid(struct oid *oid, ip4_addr addr); +#define POPULATE_BGP4(addr, proto, conn, stats, config) populate_bgp4(p, c, &(addr), &(proto), &(conn), &(stats), &(config)) +static inline void ip4_to_oid(struct oid *oid, ip4_addr addr); + static inline void snmp_hash_add_peer(struct snmp_proto *p, struct snmp_bgp_peer *peer) { @@ -83,7 +93,7 @@ bgp_get_candidate(u32 field) /* * First value is in secord cell of array translation_table, as the - * SNMP_BPG_IDENTIFIER == 1 + * SNMP_BGP_IDENTIFIER == 1 */ if (field > 0 && field <= ARRAY_SIZE(translation_table)- 1) return translation_table[field]; @@ -193,25 +203,22 @@ snmp_bgp_state(const struct oid *oid) return state; } -void -snmp_bgp_reg_ok(struct snmp_proto *p, struct agentx_response *r, struct oid *oid) +static void +snmp_bgp_reg_ok(struct snmp_proto *p, const struct agentx_response *res, struct snmp_registration *reg) { - (void)p; - (void)r; + const struct oid * const oid = reg->oid; (void)oid; - /* TODO: EXPENSIVE_CHECK() that - const struct oid *in_buf = ((void *) r) + sizeof(r); - struct oid *dup = snmp_prefixize(p, in_buf); - ASSUME(snmp_bgp_state(oid) == snmp_bgp_state(dup)); - mb_free(dup); - */ + (void)p; + (void) res; } -void -snmp_bgp_reg_failed(struct snmp_proto *p, struct agentx_response UNUSED *r, struct oid UNUSED *oid) +static void +snmp_bgp_reg_failed(struct snmp_proto *p, const struct agentx_response *res, struct snmp_registration *reg) { - // TODO add more sensible action - snmp_stop_subagent(p); + const struct oid * const oid = reg->oid; + (void) res; + (void)oid; + (void)p; } /* @@ -280,8 +287,9 @@ snmp_bgp_notify_common(struct snmp_proto *p, uint type, ip4_addr ip4, char last_ ip4_to_oid(addr, ip4); } /* We have enough space inside the TX-buffer prepared */ - struct snmp_pdu sink = { 0 }; - snmp_varbind_ip4(addr_vb, &sink, ip4); + struct snmp_pdu dummy = { 0 }; + dummy.sr_vb_start = addr_vb; + snmp_varbind_ip4(&dummy, ip4); { /* BGP4-MIB::bgpPeerLastError */ struct oid *error = &error_vb->name; @@ -294,7 +302,9 @@ snmp_bgp_notify_common(struct snmp_proto *p, uint type, ip4_addr ip4, char last_ error->ids[ENTRY_TYPE] = BGP4_MIB_LAST_ERROR; ip4_to_oid(error, ip4); } - snmp_varbind_nstr(error_vb, &sink, last_error, 2); + + dummy.sr_vb_start = error_vb; + snmp_varbind_nstr(&dummy, last_error, 2); { /* BGP4-MIB::bgpPeerState */ struct oid *state = &state_vb->name; @@ -307,7 +317,9 @@ snmp_bgp_notify_common(struct snmp_proto *p, uint type, ip4_addr ip4, char last_ state->ids[ENTRY_TYPE] = BGP4_MIB_STATE; ip4_to_oid(state, ip4); } - snmp_varbind_int(state_vb, &sink, state_val); + + dummy.sr_vb_start = state_vb; + snmp_varbind_int(&dummy, state_val); /* We do not send the systemUpTime.0 */ snmp_notify_pdu(p, head, data, sz, 0); @@ -364,9 +376,10 @@ snmp_bgp_notify_backward_trans(struct snmp_proto *p, struct bgp_proto *bgp) } void -snmp_bgp_register(struct snmp_proto *p) +snmp_bgp4_register(struct snmp_proto *p) { u32 bgp_mib_prefix[] = { 1, 15 }; + // TODO { /* Register the whole BGP4-MIB::bgp root tree node */ @@ -380,6 +393,8 @@ snmp_bgp_register(struct snmp_proto *p) memcpy(oid->ids, bgp_mib_prefix, sizeof(bgp_mib_prefix)); reg->oid = oid; + reg->reg_hook_ok = snmp_bgp_reg_ok; + reg->reg_hook_fail = snmp_bgp_reg_failed; /* * We set both upper bound and index to zero, therefore only single OID @@ -390,7 +405,7 @@ snmp_bgp_register(struct snmp_proto *p) } static int -snmp_bgp_valid_ip4(struct oid *o) +snmp_bgp_valid_ip4(const struct oid *o) { return snmp_valid_ip4_index(o, 5); } @@ -586,6 +601,565 @@ oid_state_compare(const struct oid *oid, u8 state) return -1; } +static inline enum snmp_search_res +populate_bgp4(struct snmp_proto *p, struct snmp_pdu *c, ip4_addr *addr, const struct bgp_proto **proto, const struct bgp_conn +**conn, const struct bgp_stats **stats, const struct bgp_config **config) +{ + const struct oid * const oid = &c->sr_vb_start->name; + if (snmp_bgp_valid_ip4(oid)) + *addr = ip4_from_oid(oid); + else + return SNMP_SEARCH_NO_INSTANCE; + + struct snmp_bgp_peer *pe = snmp_hash_find(p, *addr); + if (!pe) + return SNMP_SEARCH_NO_INSTANCE; + + const struct bgp_proto *bgp_proto; + *proto = bgp_proto = pe->bgp_proto; + if (ipa_is_ip4(bgp_proto->remote_ip)) + { + log(L_ERR, "%s: Found BGP protocol instance with IPv6 address", bgp_proto->p.name); + c->error = AGENTX_RES_GEN_ERROR; + return SNMP_SEARCH_NO_INSTANCE; + } + + ip4_addr proto_ip = ipa_to_ip4(bgp_proto->remote_ip); + if (!ip4_equal(proto_ip, pe->peer_ip)) + { + /* Here, we could be in problem as the bgp_proto IP address could be changed */ + log(L_ERR, "%s: Stored hash key IP address and peer remote address differ.", + bgp_proto->p.name); + c->error = AGENTX_RES_GEN_ERROR; + return SNMP_SEARCH_NO_INSTANCE; + } + + *conn = bgp_proto->conn; + *stats = &bgp_proto->stats; + *config = bgp_proto->cf; + + return SNMP_SEARCH_OK; +} + +static enum snmp_search_res +fill_bgp_version(struct snmp_proto *p, struct snmp_pdu *c) +{ + if (c->sr_vb_start->name.n_subid != 4) + { + snmp_set_varbind_type(c->sr_vb_start, AGENTX_NO_SUCH_INSTANCE); + return SNMP_SEARCH_NO_INSTANCE; + } + + uint sz = snmp_str_size_from_len(1); + if (c->size < sz) + snmp_manage_tbuf(p, c); + + c->size -= sz; + snmp_varbind_nstr(c, BGP4_VERSIONS, 1); + return SNMP_SEARCH_OK; +} + +static enum snmp_search_res +fill_local_as(struct snmp_proto *p, struct snmp_pdu *c) +{ + if (c->size < AGENTX_TYPE_INT_SIZE) + snmp_manage_tbuf(p, c); + + snmp_varbind_int(c, p->bgp_local_as); + return SNMP_SEARCH_OK; +} + +static enum snmp_search_res +fill_peer_id(struct snmp_proto *p, struct snmp_pdu *c) +{ + enum snmp_search_res res; + DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + if (res != SNMP_SEARCH_OK) + { + (void) snmp_set_varbind_type(c->sr_vb_start, res); + return res; + } + + uint fsm_state = snmp_bgp_fsm_state(bgp_proto); + + if (c->size < AGENTX_TYPE_IP4_SIZE) + snmp_manage_tbuf(p, c); + + if (fsm_state == BGP4_MIB_OPENCONFIRM || fsm_state == BGP4_MIB_ESTABLISHED) + // TODO last + snmp_varbind_ip4(c, ip4_from_u32(bgp_proto->remote_id)); + else + snmp_varbind_ip4(c, IP4_NONE); + return SNMP_SEARCH_OK; +} + +static enum snmp_search_res +fill_peer_state(struct snmp_proto *p, struct snmp_pdu *c) +{ + enum snmp_search_res res; + DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + if (res != SNMP_SEARCH_OK) + { + (void) snmp_set_varbind_type(c->sr_vb_start, res); + return res; + } + + uint fsm_state = snmp_bgp_fsm_state(bgp_proto); + + if (c->size < AGENTX_TYPE_INT_SIZE) + snmp_manage_tbuf(p, c); + + snmp_varbind_int(c, fsm_state); + return SNMP_SEARCH_OK; +} + +static enum snmp_search_res +fill_admin_status(struct snmp_proto *p, struct snmp_pdu *c) +{ + enum snmp_search_res res; + DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + if (res != SNMP_SEARCH_OK) + { + (void) snmp_set_varbind_type(c->sr_vb_start, res); + return res; + } + + if (c->size < AGENTX_TYPE_INT_SIZE) + snmp_manage_tbuf(p, c); + + if (bgp_proto->p.disabled) + snmp_varbind_int(c, AGENTX_ADMIN_STOP); + else + snmp_varbind_int(c, AGENTX_ADMIN_START); + return SNMP_SEARCH_OK; +} + +static enum snmp_search_res +fill_neg_version(struct snmp_proto *p, struct snmp_pdu *c) +{ + enum snmp_search_res res; + DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + if (res != SNMP_SEARCH_OK) + { + (void) snmp_set_varbind_type(c->sr_vb_start, res); + return res; + } + + uint fsm_state = snmp_bgp_fsm_state(bgp_proto); + + if (c->size < AGENTX_TYPE_INT_SIZE) + snmp_manage_tbuf(p, c); + + if (fsm_state == BGP4_MIB_ESTABLISHED || fsm_state == BGP4_MIB_ESTABLISHED) + snmp_varbind_int(c, BGP4_MIB_NEGOTIATED_VER_VALUE); + else + snmp_varbind_int(c, BGP4_MIB_NEGOTIATED_VER_NO_VALUE); + return SNMP_SEARCH_OK; +} + +static enum snmp_search_res +fill_local_addr(struct snmp_proto *p, struct snmp_pdu *c) +{ + enum snmp_search_res res; + DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + if (res != SNMP_SEARCH_OK) + { + (void) snmp_set_varbind_type(c->sr_vb_start, res); + return res; + } + + if (c->size < AGENTX_TYPE_IP4_SIZE) + snmp_manage_tbuf(p, c); + + snmp_varbind_ip4(c, ipa_to_ip4(bgp_proto->local_ip)); + return SNMP_SEARCH_OK; +} + +static enum snmp_search_res +fill_local_port(struct snmp_proto *p, struct snmp_pdu *c) +{ + enum snmp_search_res res; + DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + if (res != SNMP_SEARCH_OK) + { + (void) snmp_set_varbind_type(c->sr_vb_start, res); + return res; + } + + if (c->size < AGENTX_TYPE_INT_SIZE) + snmp_manage_tbuf(p, c); + + snmp_varbind_int(c, bgp_conf->local_port); + return SNMP_SEARCH_OK; +} + +static enum snmp_search_res +fill_remove_addr(struct snmp_proto *p, struct snmp_pdu *c) +{ + enum snmp_search_res res; + DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + if (res != SNMP_SEARCH_OK) + { + (void) snmp_set_varbind_type(c->sr_vb_start, res); + return res; + } + + if (c->size < AGENTX_TYPE_IP4_SIZE) + snmp_manage_tbuf(p, c); + + snmp_varbind_ip4(c, ipa_to_ip4(bgp_proto->remote_ip)); + return SNMP_SEARCH_OK; +} + +static enum snmp_search_res +fill_remote_port(struct snmp_proto *p, struct snmp_pdu *c) +{ + enum snmp_search_res res; + DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + if (res != SNMP_SEARCH_OK) + { + (void) snmp_set_varbind_type(c->sr_vb_start, res); + return res; + } + + if (c->size < AGENTX_TYPE_INT_SIZE) + snmp_manage_tbuf(p, c); + + snmp_varbind_int(c, bgp_conf->remote_port); + return SNMP_SEARCH_OK; +} + +static enum snmp_search_res +fill_remote_as(struct snmp_proto *p, struct snmp_pdu *c) +{ + enum snmp_search_res res; + DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + if (res != SNMP_SEARCH_OK) + { + (void) snmp_set_varbind_type(c->sr_vb_start, res); + return res; + } + + if (c->size < AGENTX_TYPE_INT_SIZE) + snmp_manage_tbuf(p, c); + + snmp_varbind_int(c, bgp_proto->remote_as); + return SNMP_SEARCH_OK; +} + +static enum snmp_search_res +fill_in_updates(struct snmp_proto *p, struct snmp_pdu *c) +{ + enum snmp_search_res res; + DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + if (res != SNMP_SEARCH_OK) + { + (void) snmp_set_varbind_type(c->sr_vb_start, res); + return res; + } + + if (c->size < AGENTX_TYPE_COUNTER32_SIZE) + snmp_manage_tbuf(p, c); + + snmp_varbind_counter32(c, bgp_stats->rx_updates); + return SNMP_SEARCH_OK; +} + +static enum snmp_search_res +fill_out_update(struct snmp_proto *p, struct snmp_pdu *c) +{ + enum snmp_search_res res; + DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + if (res != SNMP_SEARCH_OK) + { + (void) snmp_set_varbind_type(c->sr_vb_start, res); + return res; + } + + if (c->size < AGENTX_TYPE_COUNTER32_SIZE) + snmp_manage_tbuf(p, c); + + snmp_varbind_counter32(c, bgp_stats->tx_updates); + return SNMP_SEARCH_OK; +} + +static enum snmp_search_res +fill_in_total_msg(struct snmp_proto *p, struct snmp_pdu *c) +{ + enum snmp_search_res res; + DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + if (res != SNMP_SEARCH_OK) + { + (void) snmp_set_varbind_type(c->sr_vb_start, res); + return res; + } + + if (c->size < AGENTX_TYPE_COUNTER32_SIZE) + snmp_manage_tbuf(p, c); + + snmp_varbind_counter32(c, bgp_stats->rx_messages); + return SNMP_SEARCH_OK; +} + +static enum snmp_search_res +fill_out_total_msg(struct snmp_proto *p, struct snmp_pdu *c) +{ + enum snmp_search_res res; + DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + if (res != SNMP_SEARCH_OK) + { + (void) snmp_set_varbind_type(c->sr_vb_start, res); + return res; + } + + if (c->size < AGENTX_TYPE_COUNTER32_SIZE) + snmp_manage_tbuf(p, c); + + snmp_varbind_counter32(c, bgp_stats->tx_messages); + return SNMP_SEARCH_OK; +} + +static enum snmp_search_res +fill_last_err(struct snmp_proto *p, struct snmp_pdu *c) +{ + enum snmp_search_res res; + DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + if (res != SNMP_SEARCH_OK) + { + (void) snmp_set_varbind_type(c->sr_vb_start, res); + return res; + } + + if (c->size < snmp_str_size_from_len(2)) + snmp_manage_tbuf(p, c); + + char last_error[2]; + snmp_bgp_last_error(bgp_proto, last_error); + + snmp_varbind_nstr(c, last_error, 2); + return SNMP_SEARCH_OK; +} + +static enum snmp_search_res +fill_established_trans(struct snmp_proto *p, struct snmp_pdu *c) +{ + enum snmp_search_res res; + DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + if (res != SNMP_SEARCH_OK) + { + (void) snmp_set_varbind_type(c->sr_vb_start, res); + return res; + } + + if (c->size < AGENTX_TYPE_COUNTER32_SIZE) + snmp_manage_tbuf(p, c); + + snmp_varbind_counter32(c, + bgp_stats->fsm_established_transitions); + return SNMP_SEARCH_OK; +} + +static enum snmp_search_res +fill_established_time(struct snmp_proto *p, struct snmp_pdu *c) +{ + enum snmp_search_res res; + DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + if (res != SNMP_SEARCH_OK) + { + (void) snmp_set_varbind_type(c->sr_vb_start, res); + return res; + } + + if (c->size < AGENTX_TYPE_COUNTER32_SIZE) + snmp_manage_tbuf(p, c); + + + snmp_varbind_gauge32(c, + (current_time() - bgp_proto->last_established) TO_S); + return SNMP_SEARCH_OK; +} + +static enum snmp_search_res +fill_retry_interval(struct snmp_proto *p, struct snmp_pdu *c) +{ + enum snmp_search_res res; + DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + if (res != SNMP_SEARCH_OK) + { + (void) snmp_set_varbind_type(c->sr_vb_start, res); + return res; + } + + if (c->size < AGENTX_TYPE_INT_SIZE) + snmp_manage_tbuf(p, c); + + snmp_varbind_int(c, bgp_conf->connect_retry_time); + return SNMP_SEARCH_OK; +} + +static enum snmp_search_res +fill_hold_time(struct snmp_proto *p, struct snmp_pdu *c) +{ + enum snmp_search_res res; + DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + if (res != SNMP_SEARCH_OK) + { + (void) snmp_set_varbind_type(c->sr_vb_start, res); + return res; + } + + if (c->size < AGENTX_TYPE_INT_SIZE) + snmp_manage_tbuf(p, c); + + snmp_varbind_int(c, (bgp_conn) ? bgp_conn->hold_time : 0); + return SNMP_SEARCH_OK; +} + +static enum snmp_search_res +fill_keep_alive(struct snmp_proto *p, struct snmp_pdu *c) +{ + enum snmp_search_res res; + DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + if (res != SNMP_SEARCH_OK) + { + (void) snmp_set_varbind_type(c->sr_vb_start, res); + return res; + } + + if (c->size < AGENTX_TYPE_INT_SIZE) + snmp_manage_tbuf(p, c); + + if (!bgp_conf->hold_time) + snmp_varbind_int(c, 0); + else + snmp_varbind_int(c, + (bgp_conn) ? bgp_conn->keepalive_time : 0); + return SNMP_SEARCH_OK; +} + +static enum snmp_search_res +fill_hold_time_conf(struct snmp_proto *p, struct snmp_pdu *c) +{ + enum snmp_search_res res; + DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + if (res != SNMP_SEARCH_OK) + { + (void) snmp_set_varbind_type(c->sr_vb_start, res); + return res; + } + + if (c->size < AGENTX_TYPE_INT_SIZE) + snmp_manage_tbuf(p, c); + + snmp_varbind_int(c, bgp_conf->hold_time); + return SNMP_SEARCH_OK; +} + +static enum snmp_search_res +fill_keep_alive_conf(struct snmp_proto *p, struct snmp_pdu *c) +{ + enum snmp_search_res res; + DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + if (res != SNMP_SEARCH_OK) + { + (void) snmp_set_varbind_type(c->sr_vb_start, res); + return res; + } + + if (c->size < AGENTX_TYPE_INT_SIZE) + snmp_manage_tbuf(p, c); + + + if (!bgp_conf->keepalive_time) + snmp_varbind_int(c, 0); + else + snmp_varbind_int(c, + (bgp_conn) ? bgp_conn->keepalive_time : 0); + return SNMP_SEARCH_OK; +} + +static enum snmp_search_res +fill_min_as_org_interval(struct snmp_proto *p, struct snmp_pdu *c) +{ + enum snmp_search_res res; + DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + if (res != SNMP_SEARCH_OK) + { + (void) snmp_set_varbind_type(c->sr_vb_start, res); + return res; + } + + /* value should be in 1..65535 but is not supported by bird */ + if (c->size < AGENTX_TYPE_INT_SIZE) + snmp_manage_tbuf(p, c); + + snmp_varbind_int(c, 0); + return SNMP_SEARCH_OK; +} + +static enum snmp_search_res +fill_route_adv_interval(struct snmp_proto *p, struct snmp_pdu *c) +{ + enum snmp_search_res res; + DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + if (res != SNMP_SEARCH_OK) + { + (void) snmp_set_varbind_type(c->sr_vb_start, res); + return res; + } + + /* value should be in 1..65535 but is not supported by bird */ + if (c->size < AGENTX_TYPE_INT_SIZE) + snmp_manage_tbuf(p, c); + + snmp_varbind_int(c, 0); + return SNMP_SEARCH_OK; +} + +static enum snmp_search_res +fill_in_update_elapsed_time(struct snmp_proto *p, struct snmp_pdu *c) +{ + enum snmp_search_res res; + DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf); + if (res != SNMP_SEARCH_OK) + { + (void) snmp_set_varbind_type(c->sr_vb_start, res); + return res; + } + + if (c->size < AGENTX_TYPE_INT_SIZE) + snmp_manage_tbuf(p, c); + + snmp_varbind_gauge32(c, + (current_time() - bgp_proto->last_rx_update) TO_S + ); + return SNMP_SEARCH_OK; +} + static struct oid * update_bgp_vb(struct snmp_proto *p, struct agentx_varbind **vb, u8 state, struct snmp_pdu *c) { @@ -892,19 +1466,26 @@ bgp_fill_dynamic(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_p if (oid_state_compare(oid, state) == 0 && snmp_bgp_valid_ip4(oid)) addr = ip4_from_oid(oid); else - return snmp_set_varbind_type(*vb, AGENTX_NO_SUCH_INSTANCE); + { + snmp_set_varbind_type(*vb, AGENTX_NO_SUCH_INSTANCE); + return; + } struct snmp_bgp_peer *pe = snmp_hash_find(p, addr); if (!pe) - return snmp_set_varbind_type(*vb, AGENTX_NO_SUCH_INSTANCE); + { + snmp_set_varbind_type(*vb, AGENTX_NO_SUCH_INSTANCE); + return; + } const struct bgp_proto *bgp_proto = pe->bgp_proto; if (!ipa_is_ip4(bgp_proto->remote_ip)) { log(L_ERR, "%s: Found BGP protocol instance with IPv6 address", bgp_proto->p.name); c->error = AGENTX_RES_GEN_ERROR; - return snmp_set_varbind_type(*vb, AGENTX_NO_SUCH_INSTANCE); + snmp_set_varbind_type(*vb, AGENTX_NO_SUCH_INSTANCE); + return; } ip4_addr proto_ip = ipa_to_ip4(bgp_proto->remote_ip); @@ -914,7 +1495,8 @@ bgp_fill_dynamic(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_p log(L_ERR, "%s: Stored hash key IP address and peer remote address differ.", bgp_proto->p.name); c->error = AGENTX_RES_GEN_ERROR; - return snmp_set_varbind_type(*vb, AGENTX_NO_SUCH_INSTANCE); + snmp_set_varbind_type(*vb, AGENTX_NO_SUCH_INSTANCE); + return; } const struct bgp_conn *bgp_conn = bgp_proto->conn; @@ -931,20 +1513,20 @@ bgp_fill_dynamic(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_p { case BGP4_MIB_S_PEER_IDENTIFIER: if (c->size < AGENTX_TYPE_IP4_SIZE) - SNMP_MANAGE_TBUF(p, vb, c); + snmp_manage_tbuf(p, c); if (fsm_state == BGP4_MIB_OPENCONFIRM || fsm_state == BGP4_MIB_ESTABLISHED) // TODO last - snmp_varbind_ip4(*vb, c, ip4_from_u32(bgp_proto->remote_id)); + ; //snmp_varbind_ip4(*vb, c, ip4_from_u32(bgp_proto->remote_id)); else - snmp_varbind_ip4(*vb, c, IP4_NONE); + ; //snmp_varbind_ip4(*vb, c, IP4_NONE); break; case BGP4_MIB_S_STATE: if (c->size < AGENTX_TYPE_INT_SIZE) - SNMP_MANAGE_TBUF(p, vb, c); + snmp_manage_tbuf(p, c); - snmp_varbind_int(*vb, c, fsm_state); + //snmp_varbind_int(*vb, c, fsm_state); break; case BGP4_MIB_S_ADMIN_STATUS: @@ -952,9 +1534,9 @@ bgp_fill_dynamic(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_p SNMP_MANAGE_TBUF(p, vb, c); if (bgp_proto->p.disabled) - snmp_varbind_int(*vb, c, AGENTX_ADMIN_STOP); + ; //snmp_varbind_int(*vb, c, AGENTX_ADMIN_STOP); else - snmp_varbind_int(*vb, c, AGENTX_ADMIN_START); + ; //snmp_varbind_int(*vb, c, AGENTX_ADMIN_START); break; @@ -962,10 +1544,12 @@ bgp_fill_dynamic(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_p if (c->size < AGENTX_TYPE_INT_SIZE) SNMP_MANAGE_TBUF(p, vb, c); + uint fsm_state = snmp_bgp_fsm_state(bgp_proto); + if (fsm_state == BGP4_MIB_ESTABLISHED || fsm_state == BGP4_MIB_ESTABLISHED) - snmp_varbind_int(*vb, c, BGP4_MIB_NEGOTIATED_VER_VALUE); + ; //snmp_varbind_int(*vb, c, BGP4_MIB_NEGOTIATED_VER_VALUE); else - snmp_varbind_int(*vb, c, BGP4_MIB_NEGOTIATED_VER_NO_VALUE); + ; //snmp_varbind_int(*vb, c, BGP4_MIB_NEGOTIATED_VER_NO_VALUE); break; @@ -973,78 +1557,78 @@ bgp_fill_dynamic(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_p if (c->size < AGENTX_TYPE_IP4_SIZE) SNMP_MANAGE_TBUF(p, vb, c); - snmp_varbind_ip4(*vb, c, ipa_to_ip4(bgp_proto->local_ip)); + ; //snmp_varbind_ip4(*vb, c, ipa_to_ip4(bgp_proto->local_ip)); break; case BGP4_MIB_S_LOCAL_PORT: if (c->size < AGENTX_TYPE_INT_SIZE) SNMP_MANAGE_TBUF(p, vb, c); - snmp_varbind_int(*vb, c, bgp_conf->local_port); + ; //snmp_varbind_int(*vb, c, bgp_conf->local_port); break; case BGP4_MIB_S_REMOTE_ADDR: if (c->size < AGENTX_TYPE_IP4_SIZE) SNMP_MANAGE_TBUF(p, vb, c); - snmp_varbind_ip4(*vb, c, ipa_to_ip4(bgp_proto->remote_ip)); + ; //snmp_varbind_ip4(*vb, c, ipa_to_ip4(bgp_proto->remote_ip)); break; case BGP4_MIB_S_REMOTE_PORT: if (c->size < AGENTX_TYPE_INT_SIZE) SNMP_MANAGE_TBUF(p, vb, c); - snmp_varbind_int(*vb, c, bgp_conf->remote_port); + ; //snmp_varbind_int(*vb, c, bgp_conf->remote_port); break; case BGP4_MIB_S_REMOTE_AS: if (c->size < AGENTX_TYPE_INT_SIZE) SNMP_MANAGE_TBUF(p, vb, c); - snmp_varbind_int(*vb, c, bgp_proto->remote_as); + ; //snmp_varbind_int(*vb, c, bgp_proto->remote_as); break; case BGP4_MIB_S_RX_UPDATES: /* bgpPeerInUpdates */ if (c->size < AGENTX_TYPE_COUNTER32_SIZE) SNMP_MANAGE_TBUF(p, vb, c); - snmp_varbind_counter32(*vb, c, bgp_stats->rx_updates); + ; //snmp_varbind_counter32(*vb, c, bgp_stats->rx_updates); break; case BGP4_MIB_S_TX_UPDATES: /* bgpPeerOutUpdate */ if (c->size < AGENTX_TYPE_COUNTER32_SIZE) SNMP_MANAGE_TBUF(p, vb, c); - snmp_varbind_counter32(*vb, c, bgp_stats->tx_updates); + ; //snmp_varbind_counter32(*vb, c, bgp_stats->tx_updates); break; case BGP4_MIB_S_RX_MESSAGES: /* bgpPeerInTotalMessages */ if (c->size < AGENTX_TYPE_COUNTER32_SIZE) SNMP_MANAGE_TBUF(p, vb, c); - snmp_varbind_counter32(*vb, c, bgp_stats->rx_messages); + ; //snmp_varbind_counter32(*vb, c, bgp_stats->rx_messages); break; case BGP4_MIB_S_TX_MESSAGES: /* bgpPeerOutTotalMessages */ if (c->size < AGENTX_TYPE_COUNTER32_SIZE) SNMP_MANAGE_TBUF(p, vb, c); - snmp_varbind_counter32(*vb, c, bgp_stats->tx_messages); + ; //snmp_varbind_counter32(*vb, c, bgp_stats->tx_messages); break; case BGP4_MIB_S_LAST_ERROR: if (c->size < snmp_str_size_from_len(2)) SNMP_MANAGE_TBUF(p, vb, c); - snmp_varbind_nstr(*vb, c, last_error, 2); + ; //snmp_varbind_nstr(*vb, c, last_error, 2); break; case BGP4_MIB_S_FSM_TRANSITIONS: if (c->size < AGENTX_TYPE_COUNTER32_SIZE) SNMP_MANAGE_TBUF(p, vb, c); - snmp_varbind_counter32(*vb, c, - bgp_stats->fsm_established_transitions); + //snmp_varbind_counter32(*vb, c, + // bgp_stats->fsm_established_transitions); break; case BGP4_MIB_S_FSM_ESTABLISHED_TIME: @@ -1052,22 +1636,22 @@ bgp_fill_dynamic(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_p SNMP_MANAGE_TBUF(p, vb, c); - snmp_varbind_gauge32(*vb, c, - (current_time() - bgp_proto->last_established) TO_S); + //snmp_varbind_gauge32(*vb, c, + // (current_time() - bgp_proto->last_established) TO_S); break; case BGP4_MIB_S_RETRY_INTERVAL: /* retry inverval value should be != 0 */ if (c->size < AGENTX_TYPE_INT_SIZE) SNMP_MANAGE_TBUF(p, vb, c); - snmp_varbind_int(*vb, c, bgp_conf->connect_retry_time); + //snmp_varbind_int(*vb, c, bgp_conf->connect_retry_time); break; case BGP4_MIB_S_HOLD_TIME: /* hold time should be == 0 or in 3..65535 */ if (c->size < AGENTX_TYPE_INT_SIZE) SNMP_MANAGE_TBUF(p, vb, c); - snmp_varbind_int(*vb, c, (bgp_conn) ? bgp_conn->hold_time : 0); + //snmp_varbind_int(*vb, c, (bgp_conn) ? bgp_conn->hold_time : 0); break; case BGP4_MIB_S_KEEPALIVE: @@ -1075,17 +1659,17 @@ bgp_fill_dynamic(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_p SNMP_MANAGE_TBUF(p, vb, c); if (!bgp_conf->hold_time) - snmp_varbind_int(*vb, c, 0); + ; //snmp_varbind_int(*vb, c, 0); else - snmp_varbind_int(*vb, c, - (bgp_conn) ? bgp_conn->keepalive_time : 0); + ; //snmp_varbind_int(*vb, c, + // (bgp_conn) ? bgp_conn->keepalive_time : 0); break; case BGP4_MIB_S_HOLD_TIME_CONFIGURED: if (c->size < AGENTX_TYPE_INT_SIZE) SNMP_MANAGE_TBUF(p, vb, c); - snmp_varbind_int(*vb, c, bgp_conf->hold_time); + //snmp_varbind_int(*vb, c, bgp_conf->hold_time); break; case BGP4_MIB_S_KEEPALIVE_CONFIGURED: @@ -1094,10 +1678,10 @@ bgp_fill_dynamic(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_p if (!bgp_conf->keepalive_time) - snmp_varbind_int(*vb, c, 0); + ; //snmp_varbind_int(*vb, c, 0); else - snmp_varbind_int(*vb, c, - (bgp_conn) ? bgp_conn->keepalive_time : 0); + ; //snmp_varbind_int(*vb, c, + // (bgp_conn) ? bgp_conn->keepalive_time : 0); break; case BGP4_MIB_S_ORIGINATION_INTERVAL: @@ -1105,7 +1689,7 @@ bgp_fill_dynamic(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_p if (c->size < AGENTX_TYPE_INT_SIZE) SNMP_MANAGE_TBUF(p, vb, c); - snmp_varbind_int(*vb, c, 0); + //snmp_varbind_int(*vb, c, 0); break; case BGP4_MIB_S_MIN_ROUTE_ADVERTISEMENT: @@ -1113,16 +1697,16 @@ bgp_fill_dynamic(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_p if (c->size < AGENTX_TYPE_INT_SIZE) SNMP_MANAGE_TBUF(p, vb, c); - snmp_varbind_int(*vb, c, 0); + //snmp_varbind_int(*vb, c, 0); break; case BGP4_MIB_S_IN_UPDATE_ELAPSED_TIME: if (c->size < AGENTX_TYPE_INT_SIZE) SNMP_MANAGE_TBUF(p, vb, c); - snmp_varbind_gauge32(*vb, c, - (current_time() - bgp_proto->last_rx_update) TO_S - ); + //snmp_varbind_gauge32(*vb, c, + //(current_time() - bgp_proto->last_rx_update) TO_S + //); break; case BGP4_MIB_S_END: @@ -1167,21 +1751,21 @@ bgp_fill_static(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_pd SNMP_MANAGE_TBUF(p, vb, c); c->size -= sz; - snmp_varbind_nstr(*vb, c, BGP4_VERSIONS, 1); + //snmp_varbind_nstr(*vb, c, BGP4_VERSIONS, 1); break; case BGP4_MIB_S_LOCAL_AS: if (c->size < AGENTX_TYPE_INT_SIZE) SNMP_MANAGE_TBUF(p, vb, c); - snmp_varbind_int(*vb, c, p->bgp_local_as); + //snmp_varbind_int(*vb, c, p->bgp_local_as); break; case BGP4_MIB_S_IDENTIFIER: if (c->size < AGENTX_TYPE_IP4_SIZE) SNMP_MANAGE_TBUF(p, vb, c); - snmp_varbind_ip4(*vb, c, p->bgp_local_id); + //snmp_varbind_ip4(*vb, c, p->bgp_local_id); break; default: diff --git a/proto/snmp/bgp_mib.h b/proto/snmp/bgp4_mib.h similarity index 89% rename from proto/snmp/bgp_mib.h rename to proto/snmp/bgp4_mib.h index e2a6ea84e..2cac7d8ca 100644 --- a/proto/snmp/bgp_mib.h +++ b/proto/snmp/bgp4_mib.h @@ -1,9 +1,29 @@ -#ifndef _BIRD_SNMP_BGP_MIB_H_ -#define _BIRD_SNMP_BGP_MIB_H_ +#ifndef _BIRD_SNMP_BGP4_MIB_H_ +#define _BIRD_SNMP_BGP4_MIB_H_ + +#ifdef _BIRD_SNMP_SUBAGENT_H_ +#define BIRD_SNMP_BGP4_SKIP +#endif #include "snmp.h" +#include "proto/bgp/bgp.h" + +void snmp_bgp4_register(struct snmp_proto *p); + +struct bgp4_mib { + enum snmp_tags tag; /* always BGP4_MIB, see subagent.h for more details */ + + ip4_addr addr; + const struct bgp_proto *bgp_proto; + const struct bgp_conn *bgp_conn; + const struct bgp_stats *bgp_stats; + const struct bgp_config *bgp_conf; +}; + #include "subagent.h" +#ifndef BIRD_SNMP_BGP4_SKIP + #define BGP4_MIB 15 /* peers attributes */ @@ -40,11 +60,6 @@ enum bgp4_mib_peer_entry_row { #define BGP4_MIB_NEGOTIATED_VER_VALUE 4 #define BGP4_MIB_NEGOTIATED_VER_NO_VALUE 0 - -void snmp_bgp_register(struct snmp_proto *p); -void snmp_bgp_reg_ok(struct snmp_proto *p, struct agentx_response *r, struct oid *oid); -void snmp_bgp_reg_failed(struct snmp_proto *p, struct agentx_response *r, struct oid *oid); - u8 snmp_bgp_get_valid(u8 state); u8 snmp_bgp_getnext_valid(u8 state); @@ -127,3 +142,5 @@ STATIC_ASSERT(BGP4_MIB_ESTABLISHED == BS_ESTABLISHED + 1); #define BGP4_MIB_BACKWARD_TRANS_NOTIFICATION 2 #endif + +#endif diff --git a/proto/snmp/config.Y b/proto/snmp/config.Y index 9067cf80c..1d7c421d9 100644 --- a/proto/snmp/config.Y +++ b/proto/snmp/config.Y @@ -18,7 +18,7 @@ CF_DEFINES CF_DECLS -CF_KEYWORDS(SNMP, PROTOCOL, BPG, LOCAL, AS, REMOTE, ADDRESS, PORT, DESCRIPTION, +CF_KEYWORDS(SNMP, PROTOCOL, BGP, LOCAL, AS, REMOTE, ADDRESS, PORT, DESCRIPTION, TIMEOUT, PRIORITY, CONTEXT, DEFAULT, MESSAGE) CF_GRAMMAR diff --git a/proto/snmp/mib_tree.c b/proto/snmp/mib_tree.c index a74c7cf95..a76723e2b 100644 --- a/proto/snmp/mib_tree.c +++ b/proto/snmp/mib_tree.c @@ -28,7 +28,7 @@ mib_mb_realloc(pool *p, void *ptr, unsigned size) } /* - *mib_tree_init - Initialize a MIB tree + * mib_tree_init - Initialize a MIB tree * @p: allocation source pool * @t: pointer to a tree being initialized * diff --git a/proto/snmp/mib_tree.h b/proto/snmp/mib_tree.h index feae332d0..14e8d7d8f 100644 --- a/proto/snmp/mib_tree.h +++ b/proto/snmp/mib_tree.h @@ -24,10 +24,13 @@ struct mib_node { u32 child_len; }; +struct mib_walk_state; + struct mib_leaf { struct mib_node_core c; enum snmp_search_res (*filler)(struct snmp_proto *p, struct snmp_pdu *c); //enum snmp_search_res (*filler)(struct snmp_proto_pdu *pc, struct agentx_varbind **vb); + int (*call_next)(struct snmp_proto *p, struct snmp_pdu *c, struct mib_walk_state *state); enum agentx_type type; int size; }; diff --git a/proto/snmp/snmp.c b/proto/snmp/snmp.c index e6067ff7f..dcc75491b 100644 --- a/proto/snmp/snmp.c +++ b/proto/snmp/snmp.c @@ -10,7 +10,7 @@ * * The SNMP protocol is divided into several parts: |snmp.c| which implements * the BIRD intergration, |subagent.c| contains functions for creating and - * parsing packets, |bgp_mib.c| takes care of the bgp MIB subtree of standard + * parsing packets, |bgp4_mib.c| takes care of the bgp MIB subtree of standard * BGP4-MIB and |snmp_utils.c| which is collections of helper functions for * working with OIDs, VarBinds. * @@ -334,14 +334,6 @@ snmp_cleanup(struct snmp_proto *p) r = NULL; } - struct snmp_registered_oid *ro, *ro2; - WALK_LIST_DELSAFE(ro, ro2, p->bgp_registered) - { - rem_node(&r->n); - mb_free(ro); - ro = NULL; - } - HASH_FREE(p->bgp_hash); rfree(p->lp); @@ -507,7 +499,6 @@ snmp_start(struct proto *P) p->ping_timer = tm_new_init(p->pool, snmp_ping_timeout, p, p->timeout, 0); init_list(&p->registration_queue); - init_list(&p->bgp_registered); /* We create copy of bonds to BGP protocols. */ HASH_INIT(p->bgp_hash, p->pool, 10); diff --git a/proto/snmp/snmp.h b/proto/snmp/snmp.h index cb80cdf4e..fde7f9950 100644 --- a/proto/snmp/snmp.h +++ b/proto/snmp/snmp.h @@ -17,8 +17,7 @@ #include "nest/bird.h" #include "nest/protocol.h" #include "filter/data.h" -#include "proto/bgp/bgp.h" - +#include "proto/bgp/bgp.h" // TODO remove me #define SNMP_UNDEFINED 0 #define SNMP_BGP 1 @@ -42,6 +41,11 @@ enum snmp_proto_state { SNMP_RESET, }; +enum snmp_tags { + EMPTY_TAG = 0, + BGP4_TAG, +}; + struct snmp_bond { node n; struct proto_config *config; @@ -81,20 +85,13 @@ struct snmp_bgp_peer { struct snmp_bgp_peer *next; }; -struct snmp_registration { - node n; - u8 mib_class; - u32 session_id; - u32 transaction_id; - u32 packet_id; - struct oid *oid; -}; - struct snmp_registered_oid { node n; struct oid *oid; }; +struct mib_tree; /* see mib_tree.h */ + struct snmp_proto { struct proto p; struct object_lock *lock; @@ -125,8 +122,6 @@ struct snmp_proto { uint registrations_to_ack; /* counter of pending responses to register-pdu */ list registration_queue; /* list containing snmp_register records */ - list bgp_registered; /* list of currently registered bgp oids - * (struct snmp_registered_oid) */ // map struct f_trie *bgp_trie; @@ -138,6 +133,23 @@ struct snmp_proto { timer *ping_timer; btime startup_delay; timer *startup_timer; + + struct mib_tree *mib_tree; +}; + +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; + u32 session_id; + u32 transaction_id; + u32 packet_id; + struct oid *oid; + snmp_reg_hook_t reg_hook_ok; /* hook called when successful response to OID registration is recieved */ + snmp_reg_hook_t reg_hook_fail; /* hook called when OID registration fail */ }; //void snmp_tx(sock *sk); diff --git a/proto/snmp/snmp_test.c b/proto/snmp/snmp_test.c index aecef3375..43b38fed1 100644 --- a/proto/snmp/snmp_test.c +++ b/proto/snmp/snmp_test.c @@ -385,7 +385,7 @@ t_oid_compare(void) bt_assert(snmp_oid_compare(no_pref2, pref2) == 0); bt_assert(snmp_oid_compare(pref, pref2) < 0); - bt_assert(snmp_oid_compare(pref2, pref) > 0); + bt_assert(snmp_oid_compare(pref2, pref) > 0); bt_assert(snmp_oid_compare(pref, no_pref2) < 0); bt_assert(snmp_oid_compare(no_pref2, pref) > 0); bt_assert(snmp_oid_compare(no_pref, pref2) < 0); @@ -1119,7 +1119,7 @@ gen_test_find(struct oid *(*generator)(void)) last = found; /* test finding with walk state not pointing at the root of the tree */ - u8 subids = LOAD_U8(oids[i]->n_subid); + u8 subids = LOAD_U8(oids[i]->n_subid); if (subids > 0) { found = NULL; @@ -1204,10 +1204,10 @@ gen_test_find(struct oid *(*generator)(void)) mib_tree_walk_init(&walk, (xrandom(2)) ? tree : NULL); STORE_U8(searched[search]->n_subid, new_ids); - + mib_node_u *ignored UNUSED; ignored = mib_tree_find(tree, &walk, searched[search]); - + STORE_U8(searched[search]->n_subid, subids); found = mib_tree_find(tree, &walk, searched[search]); @@ -1375,7 +1375,7 @@ gen_test_delete_remove(struct oid *(*generator)(void), int remove) //mib_tree_walk_init(&walk, tree, 0); mib_tree_walk_init(&walk, NULL); mib_node_u *node = mib_tree_find(tree, &walk, sorted[j]); - + if (snmp_is_oid_empty(oid)) ; /* the oid could have multiple instances in the oids dataset */ @@ -1478,7 +1478,7 @@ gen_test_traverse(struct oid *(*generator)(void)) nodes[d] = mib_tree_find(tree, &walk, sorted[d]); } - int bound = 0; + int bound = 0; for (int d = 0; d < distinct; d++) { @@ -1630,8 +1630,8 @@ gen_test_leafs(struct oid *(*generator)(void)) bt_assert(snmp_oid_compare(last, oid) < 0); bt_assert(mib_node_is_leaf(((mib_node_u *)current))); - - while (oid_index < distinct && + + while (oid_index < distinct && (nodes[oid_index] == NULL || !mib_node_is_leaf(nodes[oid_index]))) oid_index++; @@ -1646,7 +1646,7 @@ gen_test_leafs(struct oid *(*generator)(void)) current = mib_tree_walk_next_leaf(tree, &walk); bt_assert(current == NULL); - bt_assert(oid_index == distinct); + bt_assert(oid_index == distinct); bt_assert(i == leafs); mb_free(oids); diff --git a/proto/snmp/snmp_utils.c b/proto/snmp/snmp_utils.c index bb7c6efd7..76b866848 100644 --- a/proto/snmp/snmp_utils.c +++ b/proto/snmp/snmp_utils.c @@ -65,7 +65,7 @@ snmp_varbind_set_name_len(struct snmp_proto *p, struct agentx_varbind **vb, u8 l uint diff_size = (len - LOAD_U8(oid->n_subid)) * sizeof(u32); if (c->size < diff_size) { - snmp_manage_tbuf(p, (void **) vb, c); + snmp_manage_tbuf(p, c); oid = &(*vb)->name; } @@ -81,7 +81,7 @@ snmp_varbind_duplicate_hdr(struct snmp_proto *p, struct agentx_varbind **vb, str ASSUME(vb != NULL && *vb != NULL); uint hdr_size = snmp_varbind_header_size(*vb); if (c->size < hdr_size) - snmp_manage_tbuf(p, (void **) vb, c); + snmp_manage_tbuf(p, c); ASSERT(c->size >= hdr_size); byte *buffer = c->buffer; @@ -260,12 +260,38 @@ snmp_varbind_hdr_size_from_oid(const struct oid *oid) * * This function assumes valid @t. */ -inline void +inline enum snmp_search_res snmp_set_varbind_type(struct agentx_varbind *vb, enum agentx_type t) { ASSUME(t != AGENTX_INVALID); STORE_U16(vb->type, t); STORE_U16(vb->reserved, 0); + + switch (t) + { + case AGENTX_END_OF_MIB_VIEW: + return SNMP_SEARCH_END_OF_VIEW; + case AGENTX_NO_SUCH_OBJECT: + return SNMP_SEARCH_NO_OBJECT; + case AGENTX_NO_SUCH_INSTANCE: + return SNMP_SEARCH_NO_INSTANCE; + + /* valid varbind types */ + case AGENTX_INTEGER: + case AGENTX_OCTET_STRING: + case AGENTX_NULL: + case AGENTX_OBJECT_ID: + case AGENTX_IP_ADDRESS: + case AGENTX_COUNTER_32: + case AGENTX_GAUGE_32: + case AGENTX_TIME_TICKS: + case AGENTX_OPAQUE: + case AGENTX_COUNTER_64: + return SNMP_SEARCH_OK; + + default: + die("invalid varbind type"); + } } /* Internal wrapper */ @@ -660,7 +686,7 @@ snmp_oid_compare(const struct oid *left, const struct oid *right) /* check prefix */ if (LOAD_U32(left->ids[4]) < (u32) right_prefix) return -1; - else if (LOAD_U32(left->ids[4]) > (u32) right_prefix) + else if (LOAD_U32(left->ids[4]) > (u32) right_prefix) return 1; /* the right prefix is already checked (+1) */ @@ -798,45 +824,46 @@ snmp_varbind_type32(struct agentx_varbind *vb, struct snmp_pdu *c, enum agentx_t } inline void -snmp_varbind_int(struct agentx_varbind *vb, struct snmp_pdu *c, u32 val) +snmp_varbind_int(struct snmp_pdu *c, u32 val) { - snmp_varbind_type32(vb, c, AGENTX_INTEGER, val); + snmp_varbind_type32(c->sr_vb_start, c, AGENTX_INTEGER, val); } inline void -snmp_varbind_counter32(struct agentx_varbind *vb, struct snmp_pdu *c, u32 val) +snmp_varbind_counter32(struct snmp_pdu *c, u32 val) { - snmp_varbind_type32(vb, c, AGENTX_COUNTER_32, val); + snmp_varbind_type32(c->sr_vb_start, c, AGENTX_COUNTER_32, val); } inline void -snmp_varbind_ticks(struct agentx_varbind *vb, struct snmp_pdu *c, u32 val) +snmp_varbind_ticks(struct snmp_pdu *c, u32 val) { - snmp_varbind_type32(vb, c, AGENTX_TIME_TICKS, val); + snmp_varbind_type32(c->sr_vb_start, c, AGENTX_TIME_TICKS, val); } inline void -snmp_varbind_gauge32(struct agentx_varbind *vb, struct snmp_pdu *c, s64 time) +snmp_varbind_gauge32(struct snmp_pdu *c, s64 time) { - snmp_varbind_type32(vb, c, AGENTX_GAUGE_32, MAX(0, MIN(time, UINT32_MAX))); + snmp_varbind_type32(c->sr_vb_start, c, + AGENTX_GAUGE_32, MAX(0, MIN(time, UINT32_MAX))); } inline void -snmp_varbind_ip4(struct agentx_varbind *vb, struct snmp_pdu *c, ip4_addr addr) +snmp_varbind_ip4(struct snmp_pdu *c, ip4_addr addr) { - snmp_set_varbind_type(vb, AGENTX_IP_ADDRESS); - c->buffer = snmp_put_ip4(snmp_varbind_data(vb), addr); + snmp_set_varbind_type(c->sr_vb_start, AGENTX_IP_ADDRESS); + c->buffer = snmp_put_ip4(snmp_varbind_data(c->sr_vb_start), addr); } // TODO doc string, we have already the varbind prepared inline byte * -snmp_varbind_nstr2(struct agentx_varbind *vb, uint size, const char *str, uint len) +snmp_varbind_nstr2(struct snmp_pdu *c, uint size, const char *str, uint len) { if (size < snmp_str_size_from_len(len)) return NULL; - snmp_set_varbind_type(vb, AGENTX_OCTET_STRING); - return snmp_put_nstr(snmp_varbind_data(vb), str, len); + snmp_set_varbind_type(c->sr_vb_start, AGENTX_OCTET_STRING); + return snmp_put_nstr(snmp_varbind_data(c->sr_vb_start), str, len); } /* @@ -851,10 +878,10 @@ snmp_varbind_nstr2(struct agentx_varbind *vb, uint size, const char *str, uint l * more info. */ void -snmp_varbind_nstr(struct agentx_varbind *vb, struct snmp_pdu *c, const char *str, uint len) +snmp_varbind_nstr(struct snmp_pdu *c, const char *str, uint len) { - snmp_set_varbind_type(vb, AGENTX_OCTET_STRING); - c->buffer = snmp_put_nstr(snmp_varbind_data(vb), str, len); + snmp_set_varbind_type(c->sr_vb_start, AGENTX_OCTET_STRING); + c->buffer = snmp_put_nstr(snmp_varbind_data(c->sr_vb_start), str, len); } inline enum agentx_type diff --git a/proto/snmp/snmp_utils.h b/proto/snmp/snmp_utils.h index c01d82fb4..ede6a43e6 100644 --- a/proto/snmp/snmp_utils.h +++ b/proto/snmp/snmp_utils.h @@ -14,7 +14,7 @@ uint snmp_pkt_len(const byte *start, const byte *end); /* * AgentX - Variable Binding (VarBind) type utils */ -void snmp_set_varbind_type(struct agentx_varbind *vb, enum agentx_type t); +enum snmp_search_res snmp_set_varbind_type(struct agentx_varbind *vb, enum agentx_type t); enum agentx_type snmp_get_varbind_type(const struct agentx_varbind *vb); int agentx_type_size(enum agentx_type t); @@ -74,12 +74,12 @@ int snmp_test_close_reason(byte value); /* Functions filling buffer a typed value */ struct agentx_varbind *snmp_create_varbind(byte *buf, struct oid *oid); struct agentx_varbind *snmp_create_varbind_null(byte *buf); -void snmp_varbind_int(struct agentx_varbind *vb, struct snmp_pdu *c, u32 val); -void snmp_varbind_counter32(struct agentx_varbind *vb, struct snmp_pdu *c, u32 val); -void snmp_varbind_gauge32(struct agentx_varbind *vb, struct snmp_pdu *c, s64 time); -void snmp_varbind_ticks(struct agentx_varbind *vb, struct snmp_pdu *c, u32 val); -void snmp_varbind_ip4(struct agentx_varbind *vb, struct snmp_pdu *c, ip4_addr addr); -void snmp_varbind_nstr(struct agentx_varbind *vb, struct snmp_pdu *c, const char *str, uint len); +void snmp_varbind_int(struct snmp_pdu *c, u32 val); +void snmp_varbind_counter32(struct snmp_pdu *c, u32 val); +void snmp_varbind_gauge32(struct snmp_pdu *c, s64 time); +void snmp_varbind_ticks(struct snmp_pdu *c, u32 val); +void snmp_varbind_ip4(struct snmp_pdu *c, ip4_addr addr); +void snmp_varbind_nstr(struct snmp_pdu *c, const char *str, uint len); /* Raw */ byte *snmp_no_such_object(byte *buf, struct agentx_varbind *vb, struct oid *oid); diff --git a/proto/snmp/subagent.c b/proto/snmp/subagent.c index 0892e8904..21712dc09 100644 --- a/proto/snmp/subagent.c +++ b/proto/snmp/subagent.c @@ -10,8 +10,9 @@ #include "lib/unaligned.h" #include "subagent.h" +#include "mib_tree.h" #include "snmp_utils.h" -#include "bgp_mib.h" +#include "bgp4_mib.h" /* ============================================================= * Problems @@ -115,45 +116,11 @@ snmp_blank_header(struct agentx_header *h, enum agentx_pdu_types type) snmp_header(h, type, (u8) 0); } -/* - * snmp_register_ok - registration of OID was successful - * @p: SNMP protocol instance - * @res: header of agentx-Response-PDU - * @oid: OID that was successfully registered - * @class: MIB subtree of @oid - * - * Send a notification to MIB (selected by @class) about successful registration - * of @oid. - */ -static void -snmp_register_ok(struct snmp_proto *p, struct agentx_response *res, struct oid *oid, u8 UNUSED class) -{ - // todo switch based on oid type - snmp_bgp_reg_ok(p, res, oid); -} - -/* - * snmp_regsiter_failed - registration of OID failed - * @p: SNMP protocol instance - * @res: header of agentx-Response-PDU - * @oid: OID whose registration failed - * @class: MIB subtree of @oid - * - * Send a notification to MIB (selected by @class) about @oid registration - * failure. - */ -static void -snmp_register_failed(struct snmp_proto *p, struct agentx_response *res, struct oid *oid, u8 UNUSED class) -{ - // todo switch based on oid type - snmp_bgp_reg_failed(p, res, oid); -} - /* * snmp_register_ack - handle registration response * @p: SNMP protocol instance * @res: header of agentx-Response-PDU - * @class: MIB subtree associated with agentx-Register-PDU + * @class: MIB subtree associated with agentx-Register-PDU */ void snmp_register_ack(struct snmp_proto *p, struct agentx_response *res, u8 class) @@ -161,26 +128,18 @@ snmp_register_ack(struct snmp_proto *p, struct agentx_response *res, u8 class) struct snmp_registration *reg; WALK_LIST(reg, p->registration_queue) { - // todo add support for more mib trees (other than BGP4-MIB) if (snmp_registration_match(reg, &res->h, class)) { - struct snmp_registered_oid *ro = \ - mb_alloc(p->p.pool, sizeof(struct snmp_registered_oid)); - - ro->n.prev = ro->n.next = NULL; - - ro->oid = reg->oid; - rem_node(®->n); - mb_free(reg); p->registrations_to_ack--; - add_tail(&p->bgp_registered, &ro->n); - if (res->error == AGENTX_RES_NO_ERROR) - snmp_register_ok(p, res, ro->oid, class); + reg->reg_hook_ok(p, (const struct agentx_response *) res, reg); else - snmp_register_failed(p, res, ro->oid, class); + reg->reg_hook_fail(p, (const struct agentx_response *) res, reg); + + mb_free(reg->oid); + mb_free(reg); return; } } @@ -247,7 +206,7 @@ open_pdu(struct snmp_proto *p, struct oid *oid) /* 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)) - snmp_manage_tbuf(p, NULL, &c); + snmp_manage_tbuf(p, &c); struct agentx_header *h = (void *) c.buffer; ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE); @@ -293,6 +252,7 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in struct snmp_pdu c; snmp_pdu_context(&c, sk); +// TODO use more readable anonymous structure decl. #define UPTIME_SIZE \ (6 * sizeof(u32)) /* sizeof( { u32 vb_type, u32 oid_hdr, u32 ids[4] } ) */ #define TRAP0_HEADER_SIZE \ @@ -306,7 +266,7 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in /* Make sure that we have enough space in TX-buffer */ if (c.size < sz) - snmp_manage_tbuf(p, NULL, &c); + snmp_manage_tbuf(p, &c); struct agentx_header *h = (void *) c.buffer; ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE); @@ -332,7 +292,7 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in /* TODO use time from last reconfiguration instead? [config->load_time] */ btime uptime = current_time() - boot_time; - snmp_varbind_ticks(vb, &c, (uptime TO_S) / 100); + snmp_varbind_ticks(&c, (uptime TO_S) / 100); ASSUME(snmp_test_varbind(vb)); ADVANCE(c.buffer, c.size, snmp_varbind_size_unsafe(vb)); } @@ -397,11 +357,11 @@ un_register_pdu(struct snmp_proto *p, struct oid *oid, u32 bound, uint index, en #define BOUND_SIZE sizeof(u32) /* conditional +4 for upper-bound (optinal field) */ - uint sz = AGENTX_HEADER_SIZE + snmp_oid_size(oid) + + uint sz = AGENTX_HEADER_SIZE + snmp_oid_size(oid) + ((bound > 1) ? BOUND_SIZE : 0); if (c.size < sz) - snmp_manage_tbuf(p, NULL, &c); + snmp_manage_tbuf(p, &c); struct agentx_header *h = (void *) c.buffer; ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE); @@ -483,7 +443,7 @@ close_pdu(struct snmp_proto *p, enum agentx_close_reasons reason) #define REASON_SIZE sizeof(u32) if (c.size < AGENTX_HEADER_SIZE + REASON_SIZE) - snmp_manage_tbuf(p, NULL, &c); + snmp_manage_tbuf(p, &c); struct agentx_header *h = (void *) c.buffer; ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE); @@ -614,7 +574,7 @@ parse_test_set_pdu(struct snmp_proto *p, byte * const pkt_start) snmp_pdu_context(&c, sk); if (c.size < AGENTX_HEADER_SIZE) - snmp_manage_tbuf(p, NULL, &c); + snmp_manage_tbuf(p, &c); res = prepare_response(p, &c); @@ -675,7 +635,6 @@ parse_test_set_pdu(struct snmp_proto *p, byte * const pkt_start) { TRACE(D_PACKETS, "SNMP SET action failed (not writable)"); /* This is a recoverable error, we do not need to reset the connection */ - //response_err_ind(p, res, AGENTX_RES_RESOURCE_UNAVAILABLE, c.index + 1); response_err_ind(p, res, AGENTX_RES_NOT_WRITABLE, c.index + 1); } @@ -711,7 +670,7 @@ parse_sets_pdu(struct snmp_proto *p, byte * const pkt_start, enum agentx_respons struct snmp_pdu c; snmp_pdu_context(&c, p->sock); if (c.size < sizeof(struct agentx_response)) - snmp_manage_tbuf(p, NULL, &c); + snmp_manage_tbuf(p, &c); struct agentx_response *r = prepare_response(p, &c); @@ -786,6 +745,7 @@ parse_cleanup_set_pdu(struct snmp_proto *p, byte * const pkt_start) if (pkt_size != 0) { // TODO should we free even for malformed packets ?? + // TODO -> check that data is not freed return AGENTX_HEADER_SIZE; } @@ -981,8 +941,7 @@ parse_response(struct snmp_proto *p, byte *res) void snmp_register_mibs(struct snmp_proto *p) { - snmp_bgp_register(p); - /* snmp_ospf_regsiter(p); ... */ + snmp_bgp4_register(p); } /* @@ -1071,7 +1030,8 @@ snmp_get_mib_class(const struct oid *oid) * * Return 0 if the created VarBind type is endOfMibView, 1 otherwise. */ -static int +// TODO remove me +static int UNUSED snmp_get_next2(struct snmp_proto *p, struct agentx_varbind **vb_search, struct oid *o_end, struct snmp_pdu *c) { enum snmp_search_res r; @@ -1111,7 +1071,7 @@ snmp_get_next2(struct snmp_proto *p, struct agentx_varbind **vb_search, struct o o_start = &(*vb_search)->name; if (c->size < snmp_varbind_hdr_size_from_oid(o_start)) - snmp_manage_tbuf(p, (void **) vb_search, c); + snmp_manage_tbuf(p, c); snmp_set_varbind_type(*vb_search, AGENTX_END_OF_MIB_VIEW); return 0; @@ -1186,7 +1146,7 @@ snmp_get_next3(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, } if (c->size < snmp_varbind_hdr_size_from_oid(o_start)) - snmp_manage_tbuf(p, (void **) vb, c); + snmp_manage_tbuf(p, c); vb = snmp_create_varbind(c->buffer, o_start); vb->type = AGENTX_END_OF_MIB_VIEW; @@ -1368,7 +1328,7 @@ snmp_oid_prefixize(struct snmp_proto *p, const struct oid *oid, struct snmp_pdu uint oid_size = snmp_oid_size(oid); if (c->size < oid_size) - snmp_manage_tbuf(p, NULL, c); + snmp_manage_tbuf(p, c); // TODO check if the @oid is prefixable ASSERT(c->size >= oid_size); @@ -1393,7 +1353,7 @@ snmp_vb_to_tx(struct snmp_proto *p, const struct oid *oid, struct snmp_pdu *c) { uint vb_hdr_size = snmp_varbind_hdr_size_from_oid(oid); if (c->size < vb_hdr_size) - snmp_manage_tbuf(p, NULL, c); + snmp_manage_tbuf(p, c); ASSERT(c->size >= vb_hdr_size); struct agentx_varbind *vb = (void *) c->buffer; @@ -1500,6 +1460,78 @@ parse_gets_error(struct snmp_proto *p, struct snmp_pdu *c, uint len) return len + AGENTX_HEADER_SIZE; } + +static enum snmp_search_res +snmp_mib_fill2(struct snmp_proto *p, struct snmp_pdu *c, mib_node_u *mib_node) +{ + if (!mib_node || !mib_node_is_leaf(mib_node)) + { + snmp_set_varbind_type(c->sr_vb_start, AGENTX_NO_SUCH_OBJECT); + ADVANCE(c->buffer, c->size, snmp_varbind_header_size(c->sr_vb_start)); + return AGENTX_NO_SUCH_OBJECT; + } + + struct mib_leaf *leaf = &mib_node->leaf; + + return leaf->filler(p, c); +} + +void +snmp_get_pdu(struct snmp_proto *p, struct snmp_pdu *c, struct mib_walk_state *walk) +{ + mib_node_u *node; + node = mib_tree_find(p->mib_tree, walk, &c->sr_vb_start->name); + + (void) snmp_mib_fill2(p, c, node); +} + +int +snmp_get_next_pdu(struct snmp_proto *p, struct snmp_pdu *c, struct mib_walk_state *walk) +{ + mib_node_u *node; + node = mib_tree_find(p->mib_tree, walk, &c->sr_vb_start->name); + + int inclusive = c->sr_vb_start->name.include; + + int move_next; + if (!node && inclusive) + move_next = 1; + else if (!node && !inclusive) + move_next = 1; + else if (node && inclusive && mib_node_is_leaf(node)) + move_next = 0; + else if (node && inclusive) + move_next = 1; + else if (node && !inclusive) + move_next = 0; + + struct mib_leaf *leaf = &node->leaf; + if (move_next && node && mib_node_is_leaf(node)) + move_next = leaf->call_next(p, c, walk); + + if (move_next) + node = (mib_node_u *) mib_tree_walk_next_leaf(p->mib_tree, walk); + + enum snmp_search_res res; + res = snmp_mib_fill2(p, c, node); + + if (res != SNMP_SEARCH_OK) + snmp_set_varbind_type(c->sr_vb_start, AGENTX_END_OF_MIB_VIEW); + + return res == SNMP_SEARCH_OK; +} + +void +snmp_get_bulk_pdu(struct snmp_proto *p, struct snmp_pdu *c, struct mib_walk_state *walk, struct agentx_bulk_state *bulk) +{ + if (c->index >= bulk->getbulk.non_repeaters) + bulk->repeaters++; + + // store the o_start and o_end + + bulk->has_any |= snmp_get_next_pdu(p, c, walk); +} + /* * parse_gets_pdu - parse received gets PDUs * @p: SNMP protocol instance @@ -1513,9 +1545,7 @@ static uint parse_gets_pdu(struct snmp_proto *p, byte * const pkt_start) { // TODO checks for c.size underflow - //struct agentx_varbind *vb = NULL; - struct agentx_varbind *vb_start = NULL; - struct oid *o_end = NULL; + struct mib_walk_state walk; byte *pkt = pkt_start; struct agentx_header *h = (void *) pkt; @@ -1530,7 +1560,6 @@ parse_gets_pdu(struct snmp_proto *p, byte * const pkt_start) * Get-Bulk processing stops if all the varbind have type END_OF_MIB_VIEW * has_any is true if some varbind has type other than END_OF_MIB_VIEW */ - int has_any = 0; struct agentx_bulk_state bulk_state = { }; if (h->type == AGENTX_GET_BULK_PDU) { @@ -1544,6 +1573,7 @@ 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), @@ -1552,6 +1582,7 @@ parse_gets_pdu(struct snmp_proto *p, byte * const pkt_start) /* In contrast to the RFC, we use 0-based indices. */ .index = 0, .repetition = 0, + .has_any = 0, }; } @@ -1592,30 +1623,34 @@ parse_gets_pdu(struct snmp_proto *p, byte * const pkt_start) /* We don't too to check for oversided OID because the PDU has 8k size limit */ /* We create copy of OIDs outside of rx-buffer and also prefixize them */ - vb_start = snmp_vb_to_tx(p, o_start_rx, &c); - o_end = snmp_oid_to_scratch(o_end_rx); + c.sr_vb_start = snmp_vb_to_tx(p, o_start_rx, &c); + c.sr_o_end = snmp_oid_to_scratch(o_end_rx); - ASSERT(vb_start); - ASSERT(o_end); + ASSERT(c.sr_vb_start); // TODO implement failed parsing logic + ASSERT(c.sr_o_end); - if (!snmp_is_oid_empty(o_end) && snmp_oid_compare(&vb_start->name, o_end) > 0) + if (!snmp_is_oid_empty(c.sr_o_end) && + snmp_oid_compare(&c.sr_vb_start->name, c.sr_o_end) > 0) { c.error = AGENTX_RES_GEN_ERROR; return parse_gets_error(p, &c, pkt_size); } - /* TODO find mib_class, check if type is GET of GET_NEXT, act accordingly */ switch (h->type) { case AGENTX_GET_PDU: - snmp_mib_fill(p, &vb_start, &c); + snmp_get_pdu(p, &c, &walk); + //snmp_mib_fill(p, &vb_start, &c); break; case AGENTX_GET_NEXT_PDU: - snmp_get_next2(p, &vb_start, o_end, &c); + snmp_get_next_pdu(p, &c, &walk); + //snmp_get_next2(p, &vb_start, o_end, &c); break; case AGENTX_GET_BULK_PDU: + snmp_get_bulk_pdu(p, &c, &walk, &bulk_state); + #if 0 if (c.index >= bulk_state.getbulk.non_repeaters) bulk_state.repeaters++; @@ -1624,14 +1659,15 @@ parse_gets_pdu(struct snmp_proto *p, byte * const pkt_start) /* The behavior of GetBulk pdu in the first iteration is * identical to GetNext pdu. */ has_any = snmp_get_next2(p, &vb_start, o_end, &c) || has_any; + #endif break; default: die("incorrect usage"); } - vb_start = NULL; - o_end = NULL; + c.sr_vb_start = NULL; + c.sr_o_end = NULL; c.index++; } /* while (c.error == AGENTX_RES_NO_ERROR && size > 0) */ @@ -1641,6 +1677,7 @@ parse_gets_pdu(struct snmp_proto *p, byte * const pkt_start) if (h->type == AGENTX_GET_BULK_PDU) { #if 0 + // TODO for (bulk_state.repetition++; has_any && bulk_state.repetition < bulk_state.getbulk.max_repetitions; bulk_state.repetition++) @@ -1660,6 +1697,7 @@ parse_gets_pdu(struct snmp_proto *p, byte * const pkt_start) /* We send the message in TX-buffer. */ sk_send(sk, s); + // TODO think through the error state /* number of bytes parsed from RX-buffer */ @@ -2022,6 +2060,7 @@ snmp_prefixize(struct snmp_proto *proto, const struct oid *oid) static void snmp_mib_fill(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_pdu *c) { + (void) p; ASSUME(vb != NULL && *vb != NULL); struct oid *oid = &((*vb)->name); @@ -2037,7 +2076,7 @@ snmp_mib_fill(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_pdu switch (mib_class) { case SNMP_CLASS_BGP: - snmp_bgp_fill(p, vb, c); + //snmp_bgp_fill(p, vb, c); break; case SNMP_CLASS_INVALID: @@ -2050,7 +2089,26 @@ snmp_mib_fill(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_pdu } /* - * snmp_manage_tbuf - handle situation with too short transmit buffer + * 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; + + log(L_INFO "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 * @@ -2058,7 +2116,7 @@ snmp_mib_fill(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_pdu * are invalidated! */ void -snmp_manage_tbuf(struct snmp_proto *p, void **ptr, struct snmp_pdu *c) +snmp_manage_tbuf2(struct snmp_proto *p, void **ptr, struct snmp_pdu *c) { sock *sk = p->sock; int diff; @@ -2069,7 +2127,6 @@ snmp_manage_tbuf(struct snmp_proto *p, void **ptr, struct snmp_pdu *c) sk_set_tbsize(sk, sk->tbsize + 2048); c->size += 2048; - if (ptr) *ptr = sk->tbuf + diff; } diff --git a/proto/snmp/subagent.h b/proto/snmp/subagent.h index 9701ba414..93db65f29 100644 --- a/proto/snmp/subagent.h +++ b/proto/snmp/subagent.h @@ -191,11 +191,6 @@ struct agentx_octet_str { byte data[0]; }; -struct agentx_getbulk { - u16 non_repeaters; - u16 max_repetitions; -}; - struct agentx_response { struct agentx_header h; u32 uptime; @@ -219,11 +214,17 @@ struct agentx_un_register_hdr { u8 reserved; /* always zero filled */ }; +struct agentx_getbulk { + u16 non_repeaters; + u16 max_repetitions; +}; + struct agentx_bulk_state { struct agentx_getbulk getbulk; u16 index; u16 repetition; u32 repeaters; + int has_any; /* flag is clear when all responses are EndOfMibView */ }; enum agentx_pdu_types { @@ -292,17 +293,29 @@ enum agentx_response_errs { AGENTX_RES_PROCESSING_ERR = 268, /* processingError */ } PACKED; -/* SNMP PDU TX-buffer info */ +/* SNMP PDU info */ struct snmp_pdu { + /* TX buffer */ byte *buffer; /* pointer to buffer */ uint size; /* unused space in buffer */ + + /* Search Range */ + struct agentx_varbind *sr_vb_start; /* search range starting OID inside TX buffer (final storage) */ + struct oid *sr_o_end; /* search range ending OID */ + + /* Control */ enum agentx_response_errs error; /* storage for result of current action */ u32 index; /* index on which the error was found */ + + union snmp_mibs_data *mibs_data; /* data passed from MIB search phase to MIB fill phase */ }; -struct snmp_proto_pdu { - struct snmp_proto *p; - struct snmp_pdu *c; +#include "bgp4_mib.h" + +union snmp_mibs_data { + enum snmp_tags empty; + + struct bgp4_mib bgp4; }; struct snmp_packet_info { @@ -331,7 +344,7 @@ 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, void **ptr, struct snmp_pdu *c); +void snmp_manage_tbuf(struct snmp_proto *p, struct snmp_pdu *c); struct agentx_varbind *snmp_vb_to_tx(struct snmp_proto *p, const struct oid *oid, struct snmp_pdu *c); u8 snmp_get_mib_class(const struct oid *oid); -- 2.47.2