* 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 "bgp4_mib.h"
+#include "mib_tree.h"
/* hash table macros */
#define SNMP_HASH_KEY(n) n->peer_ip
/* hash table only store ip4 addresses */
#define SNMP_HASH_LESS(ip1, ip2) SNMP_HASH_LESS4(ip1,ip2)
-// TODO delete me
+// delete me
#define SNMP_MANAGE_TBUF(...) (void)0
#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
-
-#define POPULATE_BGP4(addr, proto, conn, stats, config) populate_bgp4(p, c, &(addr), &(proto), &(conn), &(stats), &(config))
+ const struct bgp_proto UNUSED *proto; \
+ const struct bgp_conn UNUSED *conn; \
+ const struct bgp_stats UNUSED *stats; \
+ const struct bgp_config UNUSED *config
+#define POPULATE_BGP4(addr, proto, conn, stats, config) populate_bgp4(d, &(addr), &(proto), &(conn), &(stats), &(config))
static inline void ip4_to_oid(struct oid *oid, ip4_addr addr);
void
snmp_bgp4_register(struct snmp_proto *p)
{
- u32 bgp_mib_prefix[] = { 1, 15 };
- // TODO
+ u32 bgp_mib_prefix[] = { 1, BGP4_MIB }; // TODO remove constant
{
/* Register the whole BGP4-MIB::bgp root tree node */
}
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
+populate_bgp4(struct snmp_data *d, 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;
+ const struct oid * const oid = &d->c->sr_vb_start->name;
if (snmp_bgp_valid_ip4(oid))
*addr = ip4_from_oid(oid);
else
+ {
+ snmp_log("populate() invalid ip4");
return SNMP_SEARCH_NO_INSTANCE;
+ }
- struct snmp_bgp_peer *pe = snmp_hash_find(p, *addr);
+ struct snmp_bgp_peer *pe = snmp_hash_find(d->p, *addr);
if (!pe)
+ {
+ snmp_log("populate() hash find failed");
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))
+ 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;
+ log(L_ERR "%s: Found BGP protocol instance with IPv6 address", bgp_proto->p.name);
+ d->c->error = AGENTX_RES_GEN_ERROR;
return SNMP_SEARCH_NO_INSTANCE;
}
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;
+ log(L_ERR "%s: Stored hash key IP address and peer remote address differ "
+ "(%I, %I).", bgp_proto->p.name, proto_ip, pe->peer_ip);
+ d->c->error = AGENTX_RES_GEN_ERROR;
return SNMP_SEARCH_NO_INSTANCE;
}
*stats = &bgp_proto->stats;
*config = bgp_proto->cf;
+ snmp_log("populate() ok");
return SNMP_SEARCH_OK;
}
static enum snmp_search_res
-fill_bgp_version(struct snmp_proto *p, struct snmp_pdu *c)
+fill_bgp_version(struct mib_walk_state *walk UNUSED, struct snmp_data *d)
{
- 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);
+ snmp_log("fill ver");
+ d->c->size -= snmp_str_size_from_len(1);
+ snmp_varbind_nstr(d->c, BGP4_VERSIONS, 1);
return SNMP_SEARCH_OK;
}
static enum snmp_search_res
-fill_local_as(struct snmp_proto *p, struct snmp_pdu *c)
+fill_local_as(struct mib_walk_state *walk UNUSED, struct snmp_data *d)
{
- if (c->size < AGENTX_TYPE_INT_SIZE)
- snmp_manage_tbuf(p, c);
-
- snmp_varbind_int(c, p->bgp_local_as);
+ snmp_log("fill as");
+ snmp_varbind_int(d->c, d->p->bgp_local_as);
return SNMP_SEARCH_OK;
}
static enum snmp_search_res
-fill_peer_id(struct snmp_proto *p, struct snmp_pdu *c)
+fill_peer_id(struct mib_walk_state *walk UNUSED, struct snmp_data *d)
{
+ snmp_log("fill peer id");
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));
+ snmp_varbind_ip4(d->c, ip4_from_u32(bgp_proto->remote_id));
else
- snmp_varbind_ip4(c, IP4_NONE);
+ snmp_varbind_ip4(d->c, IP4_NONE);
return SNMP_SEARCH_OK;
}
static enum snmp_search_res
-fill_peer_state(struct snmp_proto *p, struct snmp_pdu *c)
+fill_peer_state(struct mib_walk_state *walk UNUSED, struct snmp_data *d)
{
+ snmp_log("fill peer state");
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);
+ snmp_varbind_int(d->c, fsm_state);
return SNMP_SEARCH_OK;
}
static enum snmp_search_res
-fill_admin_status(struct snmp_proto *p, struct snmp_pdu *c)
+fill_admin_status(struct mib_walk_state *walk UNUSED, struct snmp_data *d)
{
+ snmp_log("fill adm status");
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);
+ snmp_varbind_int(d->c, AGENTX_ADMIN_STOP);
else
- snmp_varbind_int(c, AGENTX_ADMIN_START);
+ snmp_varbind_int(d->c, AGENTX_ADMIN_START);
return SNMP_SEARCH_OK;
}
static enum snmp_search_res
-fill_neg_version(struct snmp_proto *p, struct snmp_pdu *c)
+fill_neg_version(struct mib_walk_state *walk UNUSED, struct snmp_data *d)
{
+ snmp_log("fill neg ver");
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);
+ snmp_varbind_int(d->c, BGP4_MIB_NEGOTIATED_VER_VALUE);
else
- snmp_varbind_int(c, BGP4_MIB_NEGOTIATED_VER_NO_VALUE);
+ snmp_varbind_int(d->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)
+fill_local_addr(struct mib_walk_state *walk UNUSED, struct snmp_data *d)
{
+ snmp_log("bgp4_mib fill local addr");
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);
+
+ snmp_log("fill local addr result %u", res);
+
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));
+ snmp_varbind_ip4(d->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)
+fill_local_port(struct mib_walk_state *walk UNUSED, struct snmp_data *d)
{
+ snmp_log("bgp4_mib fill local port");
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);
+ snmp_varbind_int(d->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)
+fill_remote_addr(struct mib_walk_state *walk UNUSED, struct snmp_data *d)
{
+ snmp_log("bgp4_mib fill remote addr");
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));
+ snmp_varbind_ip4(d->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)
+fill_remote_port(struct mib_walk_state *walk UNUSED, struct snmp_data *d)
{
+ snmp_log("bgp4_mib fill remote port");
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);
+ snmp_varbind_int(d->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)
+fill_remote_as(struct mib_walk_state *walk UNUSED, struct snmp_data *d)
{
+ snmp_log("fill rem as");
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);
+ snmp_varbind_int(d->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)
+fill_in_updates(struct mib_walk_state *walk UNUSED, struct snmp_data *d)
{
+ snmp_log("fill in updates");
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);
+ snmp_varbind_counter32(d->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)
+fill_out_updates(struct mib_walk_state *walk UNUSED, struct snmp_data *d)
{
+ snmp_log("fill out updates");
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);
+ snmp_varbind_counter32(d->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)
+fill_in_total_msg(struct mib_walk_state *walk UNUSED, struct snmp_data *d)
{
+ snmp_log("fill in total");
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);
+ snmp_varbind_counter32(d->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)
+fill_out_total_msg(struct mib_walk_state *walk UNUSED, struct snmp_data *d)
{
+ snmp_log("fill out total");
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);
+ snmp_varbind_counter32(d->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)
+fill_last_err(struct mib_walk_state *walk UNUSED, struct snmp_data *d)
{
+ snmp_log("fill last err");
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);
+ snmp_varbind_nstr(d->c, last_error, 2);
return SNMP_SEARCH_OK;
}
static enum snmp_search_res
-fill_established_trans(struct snmp_proto *p, struct snmp_pdu *c)
+fill_established_trans(struct mib_walk_state *walk UNUSED, struct snmp_data *d)
{
+ snmp_log("fill est trans");
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,
+ snmp_varbind_counter32(d->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)
+fill_established_time(struct mib_walk_state *walk UNUSED, struct snmp_data *d)
{
+ snmp_log("fill est time");
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,
+ snmp_varbind_gauge32(d->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)
+fill_retry_interval(struct mib_walk_state *walk UNUSED, struct snmp_data *d)
{
+ snmp_log("fill retry int");
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);
+ snmp_varbind_int(d->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)
+fill_hold_time(struct mib_walk_state *walk UNUSED, struct snmp_data *d)
{
+ snmp_log("fill hold time");
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);
+ snmp_varbind_int(d->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)
+fill_keep_alive(struct mib_walk_state *walk UNUSED, struct snmp_data *d)
{
+ snmp_log("fill keepalive");
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);
+ snmp_varbind_int(d->c, 0);
else
- snmp_varbind_int(c,
+ snmp_varbind_int(d->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)
+fill_hold_time_conf(struct mib_walk_state *walk UNUSED, struct snmp_data *d)
{
+ snmp_log("fill hold time 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);
+ snmp_varbind_int(d->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)
+fill_keep_alive_conf(struct mib_walk_state *walk UNUSED, struct snmp_data *d)
{
+ snmp_log("fill keepalive 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);
+ snmp_varbind_int(d->c, 0);
else
- snmp_varbind_int(c,
+ snmp_varbind_int(d->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)
+fill_min_as_org_interval(struct mib_walk_state *walk UNUSED, struct snmp_data *d)
{
+ snmp_log("fill min org int");
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);
+ snmp_varbind_int(d->c, 0);
return SNMP_SEARCH_OK;
}
static enum snmp_search_res
-fill_route_adv_interval(struct snmp_proto *p, struct snmp_pdu *c)
+fill_route_adv_interval(struct mib_walk_state *walk UNUSED, struct snmp_data *d)
{
+ snmp_log("fill rt adv int");
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);
+ snmp_varbind_int(d->c, 0);
return SNMP_SEARCH_OK;
}
static enum snmp_search_res
-fill_in_update_elapsed_time(struct snmp_proto *p, struct snmp_pdu *c)
+fill_in_update_elapsed_time(struct mib_walk_state *walk UNUSED, struct snmp_data *d)
{
+ snmp_log("fil in elapsed");
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,
+ snmp_varbind_gauge32(d->c,
(current_time() - bgp_proto->last_rx_update) TO_S
);
return SNMP_SEARCH_OK;
}
+static enum snmp_search_res
+fill_local_id(struct mib_walk_state *walk UNUSED, struct snmp_data *d)
+{
+ snmp_log("fill local id");
+ snmp_varbind_ip4(d->c, d->p->bgp_local_id);
+ return SNMP_SEARCH_OK;
+}
+
static struct oid *
update_bgp_vb(struct snmp_proto *p, struct agentx_varbind **vb, u8 state, struct snmp_pdu *c)
{
return;
}
- const struct bgp_conn *bgp_conn = bgp_proto->conn;
- const struct bgp_stats *bgp_stats = &bgp_proto->stats;
+ //const struct bgp_conn *bgp_conn = bgp_proto->conn;
+ //const struct bgp_stats *bgp_stats = &bgp_proto->stats;
const struct bgp_config *bgp_conf = bgp_proto->cf;
uint fsm_state = snmp_bgp_fsm_state(bgp_proto);
{
case BGP4_MIB_S_PEER_IDENTIFIER:
if (c->size < AGENTX_TYPE_IP4_SIZE)
+ {
+ snmp_log("BGP4-MIB small buffer");
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_log("BGP4-MIB small buffer 2");
snmp_manage_tbuf(p, c);
+ }
//snmp_varbind_int(*vb, c, fsm_state);
break;
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;
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;
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:
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,
+ {} //snmp_varbind_int(*vb, c,
// (bgp_conn) ? bgp_conn->keepalive_time : 0);
break;
if (!bgp_conf->keepalive_time)
- ; //snmp_varbind_int(*vb, c, 0);
+ {} //snmp_varbind_int(*vb, c, 0);
else
- ; //snmp_varbind_int(*vb, c,
+ {} //snmp_varbind_int(*vb, c,
// (bgp_conn) ? bgp_conn->keepalive_time : 0);
break;
void
bgp_fill_static(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_pdu *c, u8 state)
{
+ (void)p;
ASSUME(c->buffer == snmp_varbind_data(*vb));
struct oid *oid = &(*vb)->name;
snmp_set_varbind_type(*vb, AGENTX_NO_SUCH_OBJECT);
}
+/*
+ * bgp4_next_peer
+ */
+static int UNUSED
+bgp4_next_peer(struct mib_walk_state *state, struct snmp_data *data)
+{
+ //struct agentx_varbind *vb = data->c->sr_vb_start;
+ struct oid *oid = &data->c->sr_vb_start->name;
+
+ ip4_addr ip4 = ip4_from_oid(oid);
+
+ /* 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 }
+ };
+
+ const struct oid *peer_oid = (const struct oid *) &bgp4_peer_id;
+
+ if (snmp_oid_compare(oid, peer_oid) < 0 || LOAD_U8(oid->n_subid) < 9)
+ {
+ die("unreachable?");
+
+ int old = snmp_oid_size(oid);
+ int new = snmp_oid_size(peer_oid);
+
+ if (new - old > 0 && (uint) new - old > data->c->size)
+ {
+ snmp_log("bgp4_next_peer small buffer");
+ snmp_manage_tbuf(data->p, data->c);
+ }
+
+ if (new > old)
+ data->c->buffer += (new - old);
+
+ snmp_oid_copy(oid, peer_oid);
+
+ STORE_U8(oid->include, 1);
+ }
+
+ ASSUME(oid->n_subid == 9);
+ /* +1 includes empty prefix */
+
+ net_addr net;
+ net_fill_ip4(&net, ip4, IP4_MAX_PREFIX_LENGTH);
+ struct f_trie_walk_state ws;
+
+ int match = trie_walk_init(&ws, data->p->bgp_trie, &net, 1);
+
+ if (match && LOAD_U8(oid->include))
+ {
+ STORE_U8(oid->include, 0);
+ ip4_to_oid(oid, ip4);
+ return 0;
+ }
+
+ /* We skip the first match as we should not include ip address in oid */
+ if (match)
+ (void) trie_walk_next(&ws, &net);
+
+ if (trie_walk_next(&ws, &net))
+ {
+ ASSUME(oid->n_subid == 9);
+ ip4_addr res = ipa_to_ip4(net_prefix(&net));
+ ip4_to_oid(oid, res);
+ return 0;
+ }
+
+ return 1;
+}
+
/*
* snmp_bgp_start - prepare BGP4-MIB
* @p - SNMP protocol instance holding memory pool
* It is gruaranteed that the BGP protocols exist.
*/
void
-snmp_bgp_start(struct snmp_proto *p)
+snmp_bgp4_start(struct snmp_proto *p)
{
struct snmp_config *cf = SKIP_BACK(struct snmp_config, cf, p->p.cf);
/* Create binding to BGP protocols */
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 },
+ };
+
+ (void) mib_tree_hint(p->pool, p->mib_tree,
+ (const struct oid *) &bgp4_mib_root, 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 },
+ };
+
+ struct {
+ u32 id;
+ enum snmp_search_res (*filler)(struct mib_walk_state *state, struct snmp_data *data);
+ enum agentx_type type;
+ int size;
+ } leafs[] = {
+ {
+ .id = BGP4_MIB_VERSION,
+ .filler = fill_bgp_version,
+ .type = AGENTX_OCTET_STRING,
+ .size = snmp_str_size_from_len(sizeof(BGP4_VERSIONS)),
+ },
+ {
+ .id = BGP4_MIB_LOCAL_AS,
+ .filler = fill_local_as,
+ .type = AGENTX_INTEGER,
+ },
+ {
+ .id = BGP4_MIB_IDENTIFIER,
+ .filler = fill_local_id,
+ .type = AGENTX_IP_ADDRESS,
+ },
+ };
+
+ for (uint i = 0; i < ARRAY_SIZE(leafs); i++)
+ {
+ bgp4_var.ids[ARRAY_SIZE(bgp4_var.ids) - 1] = leafs[i].id;
+ node = mib_tree_add(p->pool, p->mib_tree, (const struct oid *) &bgp4_var, 1);
+
+ ASSUME(mib_node_is_leaf(node));
+ leaf = &node->leaf;
+
+ leaf->filler = leafs[i].filler;
+ leaf->call_next = NULL; // TODO
+ leaf->type = leafs[i].type;
+ 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 },
+ };
+
+ struct {
+ enum snmp_search_res (*filler)(struct mib_walk_state *state, struct snmp_data *data);
+ enum agentx_type type;
+ int size;
+ } entry_leafs[] = {
+ [BGP4_MIB_PEER_IDENTIFIER] = {
+ .filler = fill_peer_id,
+ .type = AGENTX_IP_ADDRESS,
+ },
+ [BGP4_MIB_STATE] = {
+ .filler = fill_peer_state,
+ .type = AGENTX_INTEGER,
+ },
+ [BGP4_MIB_ADMIN_STATUS] = {
+ .filler = fill_admin_status,
+ .type = AGENTX_INTEGER,
+ },
+ [BGP4_MIB_NEGOTIATED_VERSION] = {
+ .filler = fill_neg_version,
+ .type = AGENTX_INTEGER,
+ },
+ [BGP4_MIB_LOCAL_ADDR] = {
+ .filler = fill_local_addr,
+ .type = AGENTX_IP_ADDRESS,
+ },
+ [BGP4_MIB_LOCAL_PORT] = {
+ .filler = fill_local_port,
+ .type = AGENTX_INTEGER,
+ },
+ [BGP4_MIB_REMOTE_ADDR] = {
+ .filler = fill_remote_addr,
+ .type = AGENTX_IP_ADDRESS,
+ },
+ [BGP4_MIB_REMOTE_PORT] = {
+ .filler = fill_remote_port,
+ .type = AGENTX_INTEGER,
+ },
+ [BGP4_MIB_REMOTE_AS] = {
+ .filler = fill_remote_as,
+ .type = AGENTX_INTEGER,
+ },
+ [BGP4_MIB_RX_UPDATES] = {
+ .filler = fill_in_updates,
+ .type = AGENTX_COUNTER_32,
+ },
+ [BGP4_MIB_TX_UPDATES] = {
+ .filler = fill_out_updates,
+ .type = AGENTX_COUNTER_32,
+ },
+ [BGP4_MIB_RX_MESSAGES] = {
+ .filler = fill_in_total_msg,
+ .type = AGENTX_COUNTER_32,
+ },
+ [BGP4_MIB_TX_MESSAGES] = {
+ .filler = fill_out_total_msg,
+ .type = AGENTX_COUNTER_32,
+ },
+ [BGP4_MIB_LAST_ERROR] = {
+ .filler = fill_last_err,
+ .type = AGENTX_OCTET_STRING,
+ .size = snmp_str_size_from_len(2),
+ },
+ [BGP4_MIB_FSM_TRANSITIONS] = {
+ .filler = fill_established_trans,
+ .type = AGENTX_COUNTER_32,
+ },
+ [BGP4_MIB_FSM_ESTABLISHED_TIME] = {
+ .filler = fill_established_time,
+ .type = AGENTX_GAUGE_32,
+ },
+ [BGP4_MIB_RETRY_INTERVAL] = {
+ .filler = fill_retry_interval,
+ .type = AGENTX_INTEGER,
+ },
+ [BGP4_MIB_HOLD_TIME] = {
+ .filler = fill_hold_time,
+ .type = AGENTX_INTEGER,
+ },
+ [BGP4_MIB_KEEPALIVE] = {
+ .filler = fill_keep_alive,
+ .type = AGENTX_INTEGER,
+ },
+ [BGP4_MIB_HOLD_TIME_CONFIGURED] = {
+ .filler = fill_hold_time_conf,
+ .type = AGENTX_INTEGER,
+ },
+ [BGP4_MIB_KEEPALIVE_CONFIGURED] = {
+ .filler = fill_keep_alive_conf,
+ .type = AGENTX_INTEGER,
+ },
+ [BGP4_MIB_ORIGINATION_INTERVAL] = {
+ .filler = fill_min_as_org_interval,
+ .type = AGENTX_INTEGER,
+ },
+ [BGP4_MIB_MIN_ROUTE_ADVERTISEMENT] = {
+ .filler = fill_route_adv_interval,
+ .type = AGENTX_INTEGER,
+ },
+ [BGP4_MIB_IN_UPDATE_ELAPSED_TIME] = {
+ .filler = fill_in_update_elapsed_time,
+ .type = AGENTX_GAUGE_32,
+ },
+ }; /* struct _anon entry_leafs[] */
+
+ for (enum bgp4_mib_peer_entry_row e = BGP4_MIB_PEER_IDENTIFIER;
+ e <= BGP4_MIB_IN_UPDATE_ELAPSED_TIME; e++)
+ {
+ bgp4_entry_var.ids[ARRAY_SIZE(bgp4_entry_var.ids) - 1] = (u32) e;
+ node = mib_tree_add(p->pool, p->mib_tree, (const struct oid *) &bgp4_entry_var, 1);
+
+ ASSUME(mib_node_is_leaf(node));
+ leaf = &node->leaf;
+
+ leaf->filler = entry_leafs[e].filler;
+ leaf->call_next = bgp4_next_peer;
+ leaf->type = entry_leafs[e].type;
+ leaf->size = entry_leafs[e].size;
+ }
}
static enum snmp_search_res search_mib(struct snmp_proto *p, struct agentx_varbind **vb_search, const struct oid *o_end, struct snmp_pdu *c);
+/* standard SNMP internet prefix (1.3.6.1) */
const u32 snmp_internet[] = { SNMP_ISO, SNMP_ORG, SNMP_DOD, SNMP_INTERNET };
static inline int
}
}
-
/*
* snmp_error - handle a malformed packet
* @p: SNMP protocol instance
snmp_error(struct snmp_proto *p)
{
snmp_reset(p);
- //snmp_set_state(p, SNMP_RESET);
}
/*
/* 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_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);
// TODO use more readable anonymous structure decl.
#define UPTIME_SIZE \
- (6 * sizeof(u32)) /* sizeof( { u32 vb_type, u32 oid_hdr, u32 ids[4] } ) */
+ sizeof( struct { u32 vb_type; u32 oid_hdr; u32 ids[4]; } )
#define TRAP0_HEADER_SIZE \
- (7 * sizeof(u32)) /* sizeof( { u32 vb_type, u32 oid_hdr, u32 ids[6] } ) */
+ sizeof( struct { u32 vb_type; u32 oid_hdr; u32 ids[6]; } )
uint sz = AGENTX_HEADER_SIZE + TRAP0_HEADER_SIZE + snmp_oid_size(oid) \
+ size;
/* Make sure that we have enough space in TX-buffer */
if (c.size < 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);
((bound > 1) ? BOUND_SIZE : 0);
if (c.size < 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);
#define REASON_SIZE sizeof(u32)
if (c.size < 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);
snmp_pdu_context(&c, sk);
if (c.size < AGENTX_HEADER_SIZE)
+ {
+ snmp_log("agentx-TestSet-PDU small buffer");
snmp_manage_tbuf(p, &c);
+ }
res = prepare_response(p, &c);
struct snmp_pdu c;
snmp_pdu_context(&c, p->sock);
if (c.size < sizeof(struct agentx_response))
+ {
+ snmp_log("parse_sets_pdu small buffer");
snmp_manage_tbuf(p, &c);
+ }
struct agentx_response *r = prepare_response(p, &c);
parse_pkt(struct snmp_proto *p, byte *pkt, uint size)
{
/* TX-buffer free space */
- ASSERT(snmp_is_active(p));
- if (!space_for_response(p->sock))
- return 0;
-
- ASSERT(snmp_is_active(p));
if (size < AGENTX_HEADER_SIZE)
return 0;
struct agentx_header *h = (void *) pkt;
+ if (h->flags & AGENTX_NETWORK_BYTE_ORDER)
+ {
+ TRACE(D_PACKETS, "SNMP received PDU with unexpected byte order");
+ snmp_reset(p);
+ return 0;
+ }
+
uint pkt_size = LOAD_U32(h->payload);
/* RX side checks - too big packet */
{
snmp_simple_response(p, AGENTX_RES_GEN_ERROR, 0);
snmp_reset(p);
- return 0; // TODO return size??
+ return 0; /* no bytes parsed */
}
/* This guarantees that we have the full packet already received */
p->session_id = copy.session_id;
p->transaction_id = copy.transaction_id;
p->packet_id = copy.packet_id;
- log(L_INFO "restoring packet_id %u from temporal state", p->packet_id);
+ snmp_log("restoring packet_id %u from temporal state", p->packet_id);
/*
* After unexpected state, we simply reset the session
* only sending the agentx-Response-PDU.
*/
snmp_reset(p);
- return 0; // return size??
+ return 0;
}
- ASSERT(snmp_is_active(p));
if (h->flags & AGENTX_NON_DEFAULT_CONTEXT)
{
- // TODO add non-default context support
- TRACE(D_PACKETS, "SNMP received PDU with unexpected byte order");
+ TRACE(D_PACKETS, "SNMP received PDU with non-default context");
snmp_simple_response(p, AGENTX_RES_UNSUPPORTED_CONTEXT, 0);
- /* We always accept the packet length as correct, up to set limit */
- // TODO limit
return pkt_size + AGENTX_HEADER_SIZE;
}
o_start = &(*vb_search)->name;
if (c->size < snmp_varbind_hdr_size_from_oid(o_start))
+ {
+ snmp_log("get_next2 small buffer");
snmp_manage_tbuf(p, c);
+ }
snmp_set_varbind_type(*vb_search, AGENTX_END_OF_MIB_VIEW);
return 0;
}
if (c->size < snmp_varbind_hdr_size_from_oid(o_start))
+ {
snmp_manage_tbuf(p, c);
+ }
vb = snmp_create_varbind(c->buffer, o_start);
vb->type = AGENTX_END_OF_MIB_VIEW;
uint oid_size = snmp_oid_size(oid);
if (c->size < oid_size)
+ {
snmp_manage_tbuf(p, c);
+ }
// TODO check if the @oid is prefixable
ASSERT(c->size >= oid_size);
* @c: PDU context
*
* Create NULL initialized VarBind inside TX buffer (from @c) whose vb->name is
- * @oid. The @oid is not prefixed and is prefixable, the @oid is prefixed first.
- * The protocol @p is used in cases of TX buffer space shortage.
+ * @oid. The @oid prefixed if possible. The result is stored in @c->sr_vb_start.
*/
-struct agentx_varbind *
+void
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_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;
u8 subids = LOAD_U8(oid->n_subid) - 5;
ADVANCE(c->buffer, c->size, snmp_oid_size_from_len(subids));
(void) snmp_oid_prefixize_unsafe(&vb->name, oid);
- return vb;
+
+ c->sr_vb_start = vb;
+ return;
}
ADVANCE(c->buffer, c->size, snmp_oid_size(oid));
snmp_oid_copy2(&vb->name, oid);
- return vb;
-}
-/*
- * snmp_oid_to_scratch - allocate temporal Object Identifier in prefixed form
- * @oid: prefixed Object Identifier if possible
- */
-static struct oid *
-snmp_oid_to_scratch(const struct oid *oid)
-{
- struct oid *dest;
- if (snmp_oid_is_prefixable(oid) && !snmp_oid_is_prefixed(oid))
- {
- u8 subids = LOAD_U8(oid->n_subid) - 5;
- uint prefixed_size = sizeof(struct oid) + (subids * sizeof(u32));
- dest = tmp_alloc(prefixed_size);
- snmp_oid_prefixize_unsafe(dest, oid);
-
- return dest;
- }
-
- uint oid_size = snmp_oid_size(oid);
- dest = tmp_alloc(oid_size);
- snmp_oid_copy2(dest, oid);
-
- return dest;
+ c->sr_vb_start = vb;
}
/*
{
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);
}
else if (err == AGENTX_RES_GEN_ERROR)
{
- TRACE(D_PACKETS, "Last PDU resulted in error %u", err);
+ TRACE(D_PACKETS, "Last PDU resulted in error %u genErr", err);
STORE_U32(res->index, 0);
TRACE(D_PACKETS, "Storing packet size %u (was %u)", sizeof(struct agentx_response) - AGENTX_HEADER_SIZE, LOAD_U32(res->h.payload));
STORE_U32(res->h.payload,
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)
+/*
+ * AgentX GetPDU, GetNextPDU and GetBulkPDU
+ */
+void
+snmp_get_pdu(struct snmp_proto *p, struct snmp_pdu *c, const struct oid *o_start, struct mib_walk_state *walk)
{
- 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;
- }
+ snmp_log("snmp_get_pdu()");
+ struct snmp_data d = {
+ .p = p,
+ .c = c,
+ };
- struct mib_leaf *leaf = &mib_node->leaf;
+ struct mib_leaf *leaf;
+ leaf = snmp_walk_init(p->mib_tree, walk, o_start, &d);
- return leaf->filler(p, c);
-}
+ snmp_log("found node %p", leaf);
-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);
+ enum snmp_search_res res;
+ res = snmp_walk_fill(leaf, walk, &d);
+
+ snmp_log("fill result %u", res);
- (void) snmp_mib_fill2(p, c, node);
+ if (res != SNMP_SEARCH_OK)
+ snmp_set_varbind_type(c->sr_vb_start, snmp_search_res_to_type(res));
}
int
-snmp_get_next_pdu(struct snmp_proto *p, struct snmp_pdu *c, struct mib_walk_state *walk)
+snmp_get_next_pdu(struct snmp_proto *p, struct snmp_pdu *c, const struct oid *o_start, 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);
+ struct snmp_data d = {
+ .p = p,
+ .c = c,
+ };
+
+ snmp_walk_init(p->mib_tree, walk, o_start, &d);
+ struct mib_leaf *leaf = snmp_walk_next(p->mib_tree, walk, &d);
enum snmp_search_res res;
- res = snmp_mib_fill2(p, c, node);
+ res = snmp_walk_fill(leaf, walk, &d);
if (res != SNMP_SEARCH_OK)
snmp_set_varbind_type(c->sr_vb_start, AGENTX_END_OF_MIB_VIEW);
}
void
-snmp_get_bulk_pdu(struct snmp_proto *p, struct snmp_pdu *c, struct mib_walk_state *walk, struct agentx_bulk_state *bulk)
+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)
{
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);
+ bulk->has_any |= snmp_get_next_pdu(p, c, o_start, walk);
+}
+
+static inline const struct oid *
+snmp_load_oids(byte **pkt_ptr, uint *pkt_sz, struct snmp_pdu *c)
+{
+ byte *pkt = *pkt_ptr;
+ uint pkt_size = *pkt_sz;
+
+ uint sz;
+ const struct oid *start = (const struct oid *) pkt;
+
+ if ((sz = snmp_oid_size(start)) > pkt_size)
+ {
+ snmp_log("load_oids start %u / %u", sz, pkt_size);
+ c->error = AGENTX_RES_PARSE_ERROR;
+ *pkt_ptr = pkt;
+ *pkt_sz = pkt_size;
+ return NULL;
+ }
+
+ ADVANCE(pkt, pkt_size, sz);
+
+ const struct oid *end = (const struct oid *) pkt;
+ if ((sz = snmp_oid_size(end)) > pkt_size)
+ {
+ snmp_log("load_oids end %u / %u", sz, pkt_size);
+ c->error = AGENTX_RES_PARSE_ERROR;
+ *pkt_ptr = pkt;
+ *pkt_sz = pkt_size;
+ return NULL;
+ }
+
+ ADVANCE(pkt, pkt_size, sz);
+
+ if (!snmp_is_oid_empty(end) &&
+ snmp_oid_compare(start, end) > 0)
+ {
+ c->error = AGENTX_RES_GEN_ERROR;
+ *pkt_ptr = pkt;
+ *pkt_sz = pkt_size;
+ return NULL;
+ }
+
+ ASSERT(start != NULL);
+ ASSERT(end != NULL);
+
+ c->sr_o_end = end;
+ *pkt_ptr = pkt;
+ *pkt_sz = pkt_size;
+ return start;
}
/*
static uint
parse_gets_pdu(struct snmp_proto *p, byte * const pkt_start)
{
+ snmp_log("parse_gets_pdu msg");
// TODO checks for c.size underflow
struct mib_walk_state walk;
byte *pkt = 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
*/
- struct agentx_bulk_state bulk_state = { };
+ struct agentx_bulk_state bulk_state = { 0 };
if (h->type == AGENTX_GET_BULK_PDU)
{
if (pkt_size < sizeof(struct agentx_getbulk))
{
+ snmp_log("parse_gets GetBulkPDU prepare");
c.error = AGENTX_RES_PARSE_ERROR;
c.index = 0;
return parse_gets_error(p, &c, pkt_size);
{
lp_restore(tmp_linpool, &tmps);
- /* We load search range start OID */
- const struct oid *o_start_rx = (void *) pkt;
- uint sz;
- if ((sz = snmp_oid_size(o_start_rx)) > pkt_size)
- {
- c.error = AGENTX_RES_PARSE_ERROR;
- return parse_gets_error(p, &c, pkt_size);
- }
-
- /* Update buffer pointer and remaining size counters. */
- ADVANCE(pkt, pkt_size, sz);
-
- /*
- * We load search range end OID
- * The exactly same process of sanity checking is preformed while loading
- * the SearchRange's end OID
- */
- const struct oid *o_end_rx = (void *) pkt;
- if ((sz = snmp_oid_size(o_end_rx)) > pkt_size)
- {
- c.error = AGENTX_RES_PARSE_ERROR;
- return parse_gets_error(p, &c, pkt_size);
- }
-
- ADVANCE(pkt, pkt_size, sz);
-
- /* 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 */
- 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(c.sr_vb_start); // TODO implement failed parsing logic
- ASSERT(c.sr_o_end);
-
- if (!snmp_is_oid_empty(c.sr_o_end) &&
- snmp_oid_compare(&c.sr_vb_start->name, c.sr_o_end) > 0)
+ const struct oid *start_rx;
+ if (!(start_rx = snmp_load_oids(&pkt, &pkt_size, &c)))
{
- c.error = AGENTX_RES_GEN_ERROR;
+ snmp_log("snmp_load_oid ends with an error");
return parse_gets_error(p, &c, pkt_size);
}
switch (h->type)
{
case AGENTX_GET_PDU:
- snmp_get_pdu(p, &c, &walk);
+ snmp_get_pdu(p, &c, start_rx, &walk);
//snmp_mib_fill(p, &vb_start, &c);
break;
case AGENTX_GET_NEXT_PDU:
- snmp_get_next_pdu(p, &c, &walk);
+ snmp_get_next_pdu(p, &c, start_rx, &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);
+ snmp_get_bulk_pdu(p, &c, start_rx, &walk, &bulk_state);
#if 0
if (c.index >= bulk_state.getbulk.non_repeaters)
bulk_state.repeaters++;
break;
default:
- die("incorrect usage");
+ die("implementation failure");
}
c.sr_vb_start = NULL;
int
snmp_rx(sock *sk, uint size)
{
- log(L_INFO "snmp_rx with size %u", size);
+ snmp_log("snmp_rx with size %u", size);
struct snmp_proto *p = sk->data;
byte *pkt_start = sk->rbuf;
byte *end = pkt_start + size;
void
snmp_tx(sock *sk)
{
- log(L_INFO "snmp_tx()");
+ snmp_log("snmp_tx()");
/* We still not have enough space */
if (!space_for_response(sk))
return;
ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE);
snmp_blank_header(h, AGENTX_PING_PDU);
p->packet_id++;
- log(L_INFO "incrementing packet_id to %u (ping)", p->packet_id);
+ snmp_log("incrementing packet_id to %u (ping)", p->packet_id);
snmp_session(p, h);
/* sending only header */
if (c->sr_vb_start != NULL)
diff = (void *) c->sr_vb_start - (void *) sk->tbuf;
- log(L_INFO "snmp_manage_tbuf2()");
+ snmp_log("snmp_manage_tbuf2()");
sk_set_tbsize(sk, sk->tbsize + 2048);
c->size += 2048;
if (ptr)
diff = *ptr - (void *) sk->tbuf;
- log(L_INFO "snmp_manage_tbuf()");
+ snmp_log("snmp_manage_tbuf()");
sk_set_tbsize(sk, sk->tbsize + 2048);
c->size += 2048;