/* first value is in secord cell of array translation_table (as the
* SNMP_BPG_IDENTIFIER == 1
*/
- if (field > 0 && field < sizeof(translation_table) / sizeof(translation_table[0]))
+ if (field > 0 && field <= sizeof(translation_table) / sizeof(translation_table[0]))
return translation_table[field];
+ if (field == 0)
+ return BGP_INTERNAL_INVALID;
else
- return BGP_INTERNAL_NO_VALUE;
+ return BGP_INTERNAL_END;
}
static inline struct ip4_addr
ip4_from_oid(const struct oid *o)
{
- return (o->n_subid == 9) ? ip4_build(o->ids[5], o->ids[6], o->ids[7],
-o->ids[8]) : ip4_from_u32(0xFFFFFFFF);
+ return ip4_build(
+ o->n_subid > 5 ? (o->ids[5] & 0xff) : 0,
+ o->n_subid > 6 ? (o->ids[6] & 0xff) : 0,
+ o->n_subid > 7 ? (o->ids[7] & 0xff) : 0,
+ o->n_subid > 8 ? (o->ids[8] & 0xff) : 0
+ );
}
static void
* -> BGP4-MIB::bgp (root)
*/
+ if (snmp_is_oid_empty(oid))
+ return BGP_INTERNAL_END;
+
u8 state = BGP_INTERNAL_NO_VALUE;
u8 candidate;
if (state <= BGP_INTERNAL_BGP ||
state == BGP_INTERNAL_PEER_TABLE ||
state == BGP_INTERNAL_PEER_ENTRY ||
-
- /* unsupported fields */
- state == BGP_INTERNAL_FSM_ESTABLISHED_TIME ||
- state == BGP_INTERNAL_ORIGINATION_INTERVAL ||
- state == BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT ||
- state == BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME)
- return 0; /* hasn't value */
+ state >= BGP_INTERNAL_END)
+ return 0;
else
- return 1; /* has value */
+ return 1;
}
/**
case BGP_INTERNAL_PEER_ENTRY:
return BGP_INTERNAL_IDENTIFIER;
- case BGP_INTERNAL_FSM_TRANSITIONS:
- case BGP_INTERNAL_FSM_ESTABLISHED_TIME:
- return BGP_INTERNAL_RETRY_INTERVAL;
-
-
case BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME:
-
case BGP_INTERNAL_END:
-
return BGP_INTERNAL_END;
default:
/* most likely not functioning */
if (o->prefix == 2 && o->n_subid > 0 && o->ids[0] == 1)
{
- if (o->n_subid == 2 && o->ids[1] == BGP4_MIB_VERSION ||
- o->ids[1] == BGP4_MIB_LOCAL_AS)
+ if (o->n_subid == 2 && (o->ids[1] == BGP4_MIB_VERSION ||
+ o->ids[1] == BGP4_MIB_LOCAL_AS))
return 1;
else if (o->n_subid > 2 && o->ids[1] == BGP4_PEER_TABLE &&
o->ids[2] == BGP4_PEER_ENTRY)
{
if (o->n_subid == 3)
return 1;
- if (o->n_subid == 8 &&
- o->ids[3] > 0 &&
+ if (o->n_subid == 8 && o->ids[3] > 0)
/* do not include bgpPeerInUpdatesElapsedTime
and bgpPeerFsmEstablishedTime */
- o->ids[3] < SNMP_BGP_IN_UPDATE_ELAPSED_TIME &&
- o->ids[3] != SNMP_BGP_FSM_ESTABLISHED_TIME)
+ //&& o->ids[3] < SNMP_BGP_IN_UPDATE_ELAPSED_TIME
+ //&& o->ids[3] != SNMP_BGP_FSM_ESTABLISHED_TIME)
return 1;
}
else
return 0;
}
+static int
+oid_state_compare(const struct oid *oid, u8 state)
+{
+ ASSUME(oid != NULL);
+ if (state >= BGP_INTERNAL_IDENTIFIER &&
+ state <= BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME)
+ return (oid->n_subid > 9) - (oid->n_subid < 9);
+ if (state >= BGP_INTERNAL_VERSION && state <= BGP_INTERNAL_PEER_TABLE)
+ return (oid->n_subid > 3) - (oid->n_subid < 3);
+ if (state == BGP_INTERNAL_PEER_ENTRY)
+ return (oid->n_subid > 4) - (oid->n_subid < 4);
+ if (state == BGP_INTERNAL_BGP)
+ return (oid->n_subid > 2) - (oid->n_subid < 2);
+
+ return -1;
+}
+
static struct oid *
update_bgp_oid(struct oid *oid, u8 state)
{
- ASSERT (state != BGP_INTERNAL_INVALID);
- ASSERT (state != BGP_INTERNAL_NO_VALUE);
- ASSERT (state != BGP_INTERNAL_END);
+ snmp_log("update_bgp_oid()");
+ if (state == BGP_INTERNAL_END || state == BGP_INTERNAL_INVALID ||
+ state == BGP_INTERNAL_NO_VALUE)
+ return oid;
/* if same state, no need to realloc anything */
if (snmp_bgp_state(oid) == state)
- return oid;
+ {
+ if (state >= BGP_INTERNAL_IDENTIFIER &&
+ state <= BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME &&
+ oid->n_subid == 9)
+ return oid;
+ if (state >= BGP_INTERNAL_VERSION &&
+ state <= BGP_INTERNAL_PEER_TABLE && oid->n_subid == 3)
+ return oid;
+ if (state == BGP_INTERNAL_PEER_ENTRY && oid->n_subid == 4)
+ return oid;
+ if (state == BGP_INTERNAL_BGP && oid->n_subid == 2)
+ return oid;
+ }
+ snmp_log("update work");
switch (state)
{
case BGP_INTERNAL_BGP:
/* could destroy same old data */
- oid = mb_realloc(oid, snmp_oid_sizeof(2));
+ if (oid->n_subid != 2)
+ {
+ snmp_log("realloc");
+ oid = mb_realloc(oid, snmp_oid_sizeof(2));
+ snmp_log("/realloc");
+ }
+
oid->n_subid = 2;
oid->ids[0] = 1;
oid->ids[1] = SNMP_BGP4_MIB;
break;
case BGP_INTERNAL_VERSION:
- oid = mb_realloc(oid, snmp_oid_sizeof(3));
+ if (oid->n_subid != 3)
+ { snmp_log("realloc");
+ oid = mb_realloc(oid, snmp_oid_sizeof(3));
+ snmp_log("/realloc"); }
+
oid->n_subid = 3;
oid->ids[2] = SNMP_BGP_VERSION;
break;
case BGP_INTERNAL_LOCAL_AS:
+ if (oid->n_subid != 3)
+ { snmp_log("realloc");
+ oid = mb_realloc(oid, snmp_oid_sizeof(3));
+ snmp_log("/realloc"); }
+
+ oid->n_subid = 3;
oid->ids[2] = 2;
break;
case BGP_INTERNAL_IDENTIFIER:
- oid = mb_realloc(oid, snmp_oid_sizeof(9));
- oid->n_subid = 9;
+ if (oid->n_subid != 9)
+ {
+ snmp_log("realloc");
+ oid = mb_realloc(oid, snmp_oid_sizeof(9));
+ snmp_log("/realloc");
+
+ if (oid->n_subid < 6)
+ oid->ids[5] = 0;
+ if (oid->n_subid < 7)
+ oid->ids[6] = 0;
+ if (oid->n_subid < 8)
+ oid->ids[7] = 0;
+ if (oid->n_subid < 9)
+ oid->ids[8] = 0;
+ }
+
oid->ids[2] = SNMP_BGP_PEER_TABLE;
oid->ids[3] = SNMP_BGP_PEER_ENTRY;
+
oid->ids[4] = SNMP_BGP_IDENTIFIER;
- /* zero the ip */
- oid->ids[5] = oid->ids[6] = oid->ids[7] = oid->ids[8] = 0;
+ oid->n_subid = 9;
break;
-#define SNMP_UPDATE_CASE(num, update) \
- case num: \
- oid->ids[4] = update; \
+#define SNMP_UPDATE_CASE(num, update) \
+ case num: \
+ if (oid->n_subid != 9) \
+ { \
+ snmp_log("realloc"); \
+ oid = mb_realloc(oid, snmp_oid_sizeof(9)); \
+ snmp_log("/realloc"); \
+ \
+ if (oid->n_subid < 6) \
+ oid->ids[5] = 0; \
+ if (oid->n_subid < 7) \
+ oid->ids[6] = 0; \
+ if (oid->n_subid < 8) \
+ oid->ids[7] = 0; \
+ if (oid->n_subid < 9) \
+ oid->ids[8] = 0; \
+ } \
+ oid->n_subid = 9; \
+ oid->ids[4] = update; \
break;
SNMP_UPDATE_CASE(BGP_INTERNAL_STATE, SNMP_BGP_STATE)
SNMP_UPDATE_CASE(BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT, SNMP_BGP_MIN_ROUTE_ADVERTISEMENT)
SNMP_UPDATE_CASE(BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME, SNMP_BGP_IN_UPDATE_ELAPSED_TIME)
+
+ default:
+ die("update unavailable");
}
return oid;
// TODO test bgp_find_dynamic_oid
static struct oid *
-bgp_find_dynamic_oid(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, u8 state UNUSED)
+bgp_find_dynamic_oid(struct snmp_proto *p, struct oid *o_start, const struct oid *o_end, u8 start_state)
{
+ ASSUME(o_start != NULL);
+ ASSUME(o_end != NULL);
+
snmp_log("bgp_find_dynamic_oid()");
ip4_addr ip4 = ip4_from_oid(o_start);
- /* dest is 255.255.255.255 if o_end is empty */
- ip4_addr dest = ip4_from_oid(o_end);
+ ip4_addr dest;
+
+ if (o_start->n_subid < 9)
+ o_start->include = 1;
+
+ int check_dest = snmp_is_oid_empty(o_end);
+ if (check_dest)
+ {
+ u8 end_state = snmp_bgp_state(o_end);
+ dest = (start_state == end_state && o_end->n_subid > 5) ?
+ ip4_from_oid(o_end) :
+ ip4_from_u32(0xFFFFFFFF);
+ }
snmp_log("ip addresses build (ip4) %I (dest) %I", ipa_from_ip4(ip4), ipa_from_ip4(dest));
- // why am I allocated dynamically ?!
- net_addr *net = mb_allocz(p->p.pool, sizeof(struct net_addr));
- net_fill_ip4(net, ip4, IP4_MAX_PREFIX_LENGTH);
+ net_addr net;
+ net_fill_ip4(&net, ip4, IP4_MAX_PREFIX_LENGTH);
snmp_log("dynamic part of BGP mib");
- // why am I allocated dynamically ?!
- struct f_trie_walk_state *ws = mb_allocz(p->p.pool,
- sizeof(struct f_trie_walk_state));
+ struct f_trie_walk_state ws;
- trie_walk_init(ws, p->bgp_trie, NULL);
+ // TODO move to newer API
+ trie_walk_init(&ws, p->bgp_trie, NULL, 0);
snmp_log("walk init");
- if (trie_walk_next(ws, net)) // && ip4_less(net4_prefix(net), dest))
+ if (trie_walk_next(&ws, &net)) // && ip4_less(net4_prefix(net), dest))
{
snmp_log("trie_walk_next() returned true");
/*
* if the o_end is empty then there are no conditions on the ip4 addr
*/
- int cmp = ip4_compare(net4_prefix(net), dest);
+ //int cmp = (check_dest) ? ip4_compare(net4_prefix(&net), dest) : ;
+ int cmp = ip4_compare(net4_prefix(&net), dest);
if (cmp < 0 || (cmp == 0 && snmp_is_oid_empty(o_end)))
{
snmp_log("ip4_less() returned true");
o->n_subid = 9;
memcpy(o, o_start, snmp_oid_size(o_start));
- snmp_oid_ip4_index(o, 5, net4_prefix(net));
-
- mb_free(net);
- mb_free(ws);
+ snmp_oid_ip4_index(o, 5, net4_prefix(&net));
return o;
}
// delete me
else
{
- snmp_log("ip4_less() returned false for %I >= %I", net4_prefix(net), dest);
- mb_free(net);
- mb_free(ws);
+ snmp_log("ip4_less() returned false for %I >= %I", net4_prefix(&net), dest);
}
// delete me end
}
else
{
snmp_log("trie_walk_next() returned false, cleaning");
- mb_free(net);
- mb_free(ws);
}
return NULL;
snmp_oid_dump(o_start);
next_state = snmp_bgp_next_state(next_state);
+ /* search in next state is done from beginning */
+ o_start->ids[5] = o_start->ids[6] = o_start->ids[7] = o_start->ids[8] = 0;
+ o_start->include = 1;
snmp_log("looping");
} while (o_start == NULL && next_state < BGP_INTERNAL_END);
return o_start;
}
+/**
+ * snmp_bgp_find_next_oid - walk bgp peer addresses and update @o_start oid
+ *
+ * @p:
+ * @oid:
+ * @contid:
+ */
+static int
+snmp_bgp_find_next_oid(struct snmp_proto *p, struct oid *oid, uint UNUSED contid)
+{
+ // TODO add o_end paramenter for faster searches
+ ip4_addr ip4 = ip4_from_oid(oid);
+ //ip_add4 dest = ip4_from_u32(0xFFFFFFFF);
+
+ net_addr net;
+ net_fill_ip4(&net, ip4, IP4_MAX_PREFIX_LENGTH);
+ struct f_trie_walk_state ws;
+
+ int match = trie_walk_init(&ws, p->bgp_trie, &net, 1);
+
+ snmp_log("match %d include %u", match, oid->include);
+ if (match && oid->include)
+ {
+ oid->include = 0;
+ return 1;
+ }
+
+ /* We skip the first match as we should not include ip address in oid */
+ if (match)
+ {
+ snmp_log("continue");
+ trie_walk_next(&ws, &net);
+ }
+
+ if (trie_walk_next(&ws, &net))
+ {
+ snmp_oid_dump(oid);
+ snmp_log("setting up");
+ u32 res = ipa_to_u32(net_prefix(&net));
+
+ ASSUME(oid->n_subid == 9);
+ oid->ids[5] = (res & 0xFF000000) >> 24;
+ oid->ids[6] = (res & 0x00FF0000) >> 16;
+ oid->ids[7] = (res & 0x0000FF00) >> 8;
+ oid->ids[8] = (res & 0x000000FF) >> 0;
+ return 1;
+ }
+
+ snmp_log("bad");
+ return 0;
+}
+
+static enum snmp_search_res
+snmp_bgp_search_dynamic(struct snmp_proto *p, struct oid **searched, const struct oid *o_end, uint UNUSED contid, u8 next_state)
+{
+ struct oid *oid = *searched;
+ snmp_log(" **searched = 0x%p *oid = 0x%p", searched, oid);
+ snmp_oid_dump(*searched);
+ snmp_oid_dump(oid);
+ u8 end_state = snmp_bgp_state(o_end);
+
+ snmp_log("before assumption %s [%u] < %u INTERNAL_END", debug_bgp_states[end_state], end_state, BGP_INTERNAL_END);
+ // failed
+ ASSUME(end_state <= BGP_INTERNAL_END);
+ snmp_log("before assupmtion oid 0x%p != NULL (0x0)", oid);
+ ASSUME(oid != NULL);
+
+ oid = update_bgp_oid(oid, next_state);
+
+ snmp_log("update bgp oid to state %s [%d]", debug_bgp_states[next_state], next_state);
+ snmp_oid_dump(*searched);
+ snmp_oid_dump(oid);
+
+ int found;
+ while (!(found = snmp_bgp_find_next_oid(p, oid, contid)) && next_state <= end_state)
+ {
+ snmp_log("loop");
+
+ next_state = snmp_bgp_next_state(next_state);
+ if (next_state == BGP_INTERNAL_END)
+ break;
+ oid = update_bgp_oid(oid, next_state);
+ /* in search for next bgp state, we want to start from beginning */
+ oid->ids[5] = oid->ids[6] = oid->ids[7] = oid->ids[8] = 0;
+ }
+
+ if (next_state <= end_state)
+ {
+ *searched = oid;
+ return SNMP_SEARCH_OK;
+ }
+
+ // free in the caller ?!
+ mb_free(oid);
+ *searched = NULL;
+ return SNMP_SEARCH_END_OF_VIEW;
+}
+
+enum snmp_search_res
+snmp_bgp_search2(struct snmp_proto *p, struct oid **searched, const struct oid *o_end, uint contid)
+{
+ u8 bgp_state = snmp_bgp_state(*searched);
+ struct oid *oid = *searched;
+ snmp_log("snmp_bgp_search2() with state %s [%d]", debug_bgp_states[bgp_state], bgp_state);
+
+ /* TODO remove todo below, then remove this code */
+ if (is_dynamic(bgp_state))
+ {
+ snmp_log("returning oid with dynamic state");
+ return snmp_bgp_search_dynamic(p, searched, o_end, contid, bgp_state);
+ //return snmp_bgp_search_dynamic(p, searched, contid, result, bgp_state);
+ }
+
+ /* TODO snmp_bgp_has_value is false only for state which are not dynamic */
+ if (!snmp_bgp_has_value(bgp_state) || !oid->include)
+ {
+ bgp_state = snmp_bgp_next_state(bgp_state);
+ snmp_log("altering searched oid with next state %s [%d]", debug_bgp_states[bgp_state], bgp_state);
+ snmp_oid_dump(*searched);
+ snmp_log("after oid update:");
+ snmp_oid_dump(*searched);
+
+ /* zero the ip address section for previously non-dynamic oid (search all peers) */
+ for (int i = 5; i < MIN(9, oid->n_subid); i++)
+ oid->ids[i] = 0;
+ }
+
+ if (is_dynamic(bgp_state))
+ {
+ snmp_log("returning oid with dynamic state 2");
+ return snmp_bgp_search_dynamic(p, searched, o_end, contid, bgp_state);
+ //return snmp_bgp_search_dynamic(p, o_start, contid, result, bgp_state);
+ }
+
+ oid = *searched = update_bgp_oid(*searched, bgp_state);
+ if (oid->n_subid == 3 && oid->ids[2] >= SNMP_BGP_VERSION &&
+ oid->ids[2] <= SNMP_BGP_LOCAL_AS)
+ {
+ snmp_log("oid matches static state");
+ oid->include = 0;
+ return SNMP_SEARCH_OK;
+ }
+
+ snmp_log("reached unguarded code, returning END_OF_VIEW");
+ /* TODO */
+ //if (
+
+
+ return SNMP_SEARCH_END_OF_VIEW;
+ // return SNMP_NO_SUCH_OBJECT;
+
+#if 0
+ if (is_dynamic(bgp_state))
+ return snmp_bgp_search_dynamic(p, o_start, contid, res);
+
+ if (!snmp_bgp_has_value(bgp_state))
+ {
+ bgp_state = x;
+ }
+ print_bgp_record_all(p);
+
+ if (o_start->include)
+ return snmp_bgp_search_included(p, o_start, contid, result, bgp_state);
+
+ u8 next_state = snmp_bgp_next_state(bgp_state);
+ if (!is_dynamic(next_state))
+ {
+ o_start = update_bgp_oid(o_start, next_state);
+ snmp_log("next state is also not dynamic");
+ *res = o_start;
+ return SNMP_SEARCH_OK;
+ }
+
+ return search_bgp_dynamic(p, o_start, o_end, contid, bgp_state);
+
+
+ if (o_start->include && snmp_bgp_has_value(bgp_state))
+ && !is_dynamic(bgp_state))
+ {
+ if (o_start->n_subid == 3)
+ {
+ o_start->include = 0;
+ *result = o_start;
+ return SNMP_SEARCH_OK;
+ }
+ else if (o_start->n_subid > 3)
+ return SNMP_SEARCH_NO_INSTANCE;
+ else
+ return SNMP_SEARCH_NO_OBJECT;
+ }
+ else if (o_start->include && snmp_bgp_has_value(bgp_state))
+ && is_dynamic(bgp_state))
+ return search_bgp_dynamic1(p, o_start, contid, result);
+ else if (o_start
+
+ / * o_start is not inclusive * /
+#endif
+}
+
/* o_start could be o_curr, but has basically same meaning for searching */
struct oid *
-search_bgp_mib(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, uint contid UNUSED)
+snmp_bgp_search(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, uint contid UNUSED)
{
u8 start_state = snmp_bgp_state(o_start);
//u8 state_curr = snmp_bgp_state(o_start);
if (o_start->include && snmp_bgp_has_value(start_state) &&
!is_dynamic(start_state) && o_start->n_subid == 3)
{
- snmp_log("search_bgp_mib() first search element (due to include field) returned");
+ snmp_log("snmp_bgp_search() first search element (due to include field) returned");
o_start->include = 0; /* disable including for next time */
return o_start;
}
else if (o_start->include && snmp_bgp_has_value(start_state) &&
- is_dynamic(start_state))
+ is_dynamic(start_state))
{
- snmp_log("search_bgp_mib() first search element matched dynamic entry!");
+ snmp_log("snmp_bgp_search() first search element matched dynamic entry!");
return search_bgp_dynamic(p, o_start, o_end, contid, start_state);
}
}
static byte *
-bgp_fill_dynamic(struct snmp_proto *p, struct agentx_varbind *vb, byte *pkt, uint size
-UNUSED, uint contid UNUSED, int byte_ord UNUSED, u8 state)
+bgp_fill_dynamic(struct snmp_proto UNUSED *p, struct agentx_varbind *vb,
+ struct snmp_pdu_context *c, u8 state)
{
- //snmp_log("bgp_fill_dynamic() valid ip %s", snmp_bgp_valid_ip4(oid) ? "true" : "false");
-
struct oid *oid = &vb->name;
+ uint size = c->size - snmp_varbind_header_size(vb);
+ uint UNUSED contid = c->context;
+ byte *pkt;
ip_addr addr;
- if (snmp_bgp_valid_ip4(oid))
+ if (oid_state_compare(oid, state) == 0 && snmp_bgp_valid_ip4(oid))
addr = ipa_from_ip4(ip4_from_oid(oid));
else
{
- vb->type = AGENTX_NO_SUCH_OBJECT;
+ vb->type = AGENTX_NO_SUCH_INSTANCE;
+ pkt = ((byte *) vb) + snmp_varbind_header_size(vb);
return pkt;
}
{
proto = ((struct proto_config *) pe->config)->proto;
if (proto->proto == &proto_bgp &&
- ipa_equal(addr, ((struct bgp_proto *) proto)->remote_ip))
+ ipa_equal(addr, ((struct bgp_proto *) proto)->remote_ip))
{
bgp_proto = (struct bgp_proto *) proto;
snmp_log("bgp_dynamic_fill() using bgp_proto %p", bgp_proto);
}
-
/* binded bgp protocol not found */
else
{
die("Binded bgp protocol not found!");
- vb->type = AGENTX_NO_SUCH_OBJECT;
- return pkt;
+ vb->type = AGENTX_NO_SUCH_INSTANCE;
+ return ((byte *) vb) + snmp_varbind_header_size(vb);
}
}
-
else
{
- vb->type = AGENTX_NO_SUCH_OBJECT;
- return pkt;
+ vb->type = AGENTX_NO_SUCH_INSTANCE;
+ return ((byte *) vb) + snmp_varbind_header_size(vb);
}
struct bgp_conn *bgp_conn = bgp_proto->conn;
else
bgp_state = MAX(bgp_in->state, bgp_out->state);
- btime now;
+ char last_error[2] = { bgp_proto->last_error_code & 0x00FF0000 >> 16,
+ bgp_proto->last_error_code & 0x000000FF };
switch (state)
{
-
case BGP_INTERNAL_IDENTIFIER:
if (bgp_state == BS_OPENCONFIRM || bgp_state == BS_ESTABLISHED)
- {
- snmp_put_ip4(pkt, bgp_proto->remote_ip);
- pkt += 4;
- /* the inserted ip has size 8 bytes, the BGP_DATA will increment by 4B */
- BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt);
- }
+ pkt = snmp_varbind_ip4(vb, size, ipa_to_ip4(bgp_proto->remote_ip));
else
- {
- snmp_put_blank(pkt); /* stores 4B of zeroes */
- BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt);
- }
+ pkt = snmp_varbind_ip4(vb, size, IP4_NONE);
break;
case BGP_INTERNAL_STATE:
- STORE_PTR(pkt, bgp_state);
- BGP_DATA(vb, AGENTX_INTEGER, pkt);
+ pkt = snmp_varbind_int(vb, size, bgp_state);
break;
case BGP_INTERNAL_ADMIN_STATUS:
/* struct proto ~ (struct proto *) bgp_proto */
if (proto->disabled)
- STORE_PTR(pkt, AGENTX_ADMIN_STOP);
+ pkt = snmp_varbind_int(vb, size, AGENTX_ADMIN_STOP);
else
- STORE_PTR(pkt, AGENTX_ADMIN_START);
+ pkt = snmp_varbind_int(vb, size, AGENTX_ADMIN_START);
- BGP_DATA(vb, AGENTX_INTEGER, pkt);
break;
case BGP_INTERNAL_NEGOTIATED_VERSION:
if (bgp_state == BS_OPENCONFIRM || bgp_state == BS_ESTABLISHED)
- STORE_PTR(pkt, 4); // TODO replace with MACRO
+ pkt = snmp_varbind_int(vb, size, SNMP_BGP_NEGOTIATED_VER_VALUE);
else
- STORE_PTR(pkt, 0); /* zero dictated by rfc */
+ pkt = snmp_varbind_int(vb, size, SNMP_BGP_NEGOTIATED_VER_NO_VALUE);
- BGP_DATA(vb, AGENTX_INTEGER, pkt);
break;
case BGP_INTERNAL_LOCAL_ADDR:
// TODO XXX bgp_proto->link_addr & zero local_ip
- snmp_put_ip4(pkt, bgp_proto->local_ip);
- pkt += 4;
- /* the inserted ip has size 8 bytes, the BGP_DATA will increment by 4B */
- BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt);
+ pkt = snmp_varbind_ip4(vb, size, ipa_to_ip4(bgp_proto->local_ip));
break;
case BGP_INTERNAL_LOCAL_PORT:
- STORE_PTR(pkt, bgp_conf->local_port);
- BGP_DATA(vb, AGENTX_INTEGER, pkt);
+ pkt = snmp_varbind_int(vb, size, bgp_conf->local_port);
break;
case BGP_INTERNAL_REMOTE_ADDR:
- snmp_put_ip4(pkt, bgp_proto->remote_ip);
- pkt += 4;
- /* the inserted ip has size 8 bytes, the BGP_DATA will increment by 4B */
- BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt);
+ pkt = snmp_varbind_ip4(vb, size, ipa_to_ip4(bgp_proto->remote_ip));
break;
case BGP_INTERNAL_REMOTE_PORT:
- STORE_PTR(pkt, bgp_conf->remote_port);
- BGP_DATA(vb, AGENTX_INTEGER, pkt);
+ pkt = snmp_varbind_int(vb, size, bgp_conf->remote_port);
break;
case BGP_INTERNAL_REMOTE_AS:
- STORE_PTR(pkt, bgp_proto->remote_as);
- BGP_DATA(vb, AGENTX_INTEGER, pkt);
+ pkt = snmp_varbind_int(vb, size, bgp_proto->remote_as);
break;
/* IN UPDATES */
case BGP_INTERNAL_RX_UPDATES:
- STORE_PTR(pkt, bgp_stats->rx_updates);
- BGP_DATA(vb, AGENTX_COUNTER_32, pkt);
+ pkt = snmp_varbind_counter32(vb, size, bgp_stats->rx_updates);
break;
/* OUT UPDATES */
case BGP_INTERNAL_TX_UPDATES:
- STORE_PTR(pkt, bgp_stats->tx_updates);
- BGP_DATA(vb, AGENTX_COUNTER_32, pkt);
+ pkt = snmp_varbind_counter32(vb, size, bgp_stats->tx_updates);
break;
/* IN MESSAGES */
case BGP_INTERNAL_RX_MESSAGES:
- STORE_PTR(pkt, bgp_stats->rx_messages);
- BGP_DATA(vb, AGENTX_COUNTER_32, pkt);
+ pkt = snmp_varbind_counter32(vb, size, bgp_stats->rx_messages);
break;
/* OUT MESSAGES */
case BGP_INTERNAL_TX_MESSAGES:
- STORE_PTR(pkt, bgp_stats->tx_messages);
- BGP_DATA(vb, AGENTX_COUNTER_32, pkt);
+ pkt = snmp_varbind_counter32(vb, size, bgp_stats->tx_messages);
break;
case BGP_INTERNAL_LAST_ERROR:
- STORE_PTR(pkt, 2);
- pkt += 4;
-
- if (bgp_proto->last_error_code)
- {
- /* force network order */
- put_u32(pkt, bgp_proto->last_error_code & 0x00FF0000 << 8 |
- bgp_proto->last_error_code & 0x000000FF << 24);
- }
- else
- snmp_put_blank(pkt);
-
- BGP_DATA(vb, AGENTX_OCTET_STRING, pkt);
+ pkt = snmp_varbind_nstr(vb, size, last_error, 2);
break;
// TODO finish me here
case BGP_INTERNAL_FSM_TRANSITIONS:
- STORE_PTR(pkt, bgp_stats->fsm_established_transitions);
- BGP_DATA(vb, AGENTX_COUNTER_32, pkt);
+ pkt = snmp_varbind_counter32(vb, size,
+ bgp_stats->fsm_established_transitions);
break;
case BGP_INTERNAL_FSM_ESTABLISHED_TIME:
+ pkt = snmp_varbind_gauge32(vb, size,
+ (current_time() - bgp_proto->last_established) TO_S);
break;
case BGP_INTERNAL_RETRY_INTERVAL:
// retry interval != 0
- STORE_PTR(pkt, bgp_conf->connect_retry_time);
- BGP_DATA(vb, AGENTX_INTEGER, pkt);
+ pkt = snmp_varbind_int(vb, size, bgp_conf->connect_retry_time);
break;
case BGP_INTERNAL_HOLD_TIME:
// (0, 3..65535)
- STORE_PTR(pkt, bgp_conn->hold_time);
- BGP_DATA(vb, AGENTX_INTEGER, pkt);
+ pkt = snmp_varbind_int(vb, size, bgp_conn->hold_time);
break;
case BGP_INTERNAL_KEEPALIVE:
- STORE_PTR(pkt, bgp_conn->keepalive_time);
- BGP_DATA(vb, AGENTX_INTEGER, pkt);
+ pkt = snmp_varbind_int(vb, size, bgp_conn->keepalive_time);
break;
case BGP_INTERNAL_HOLD_TIME_CONFIGURED:
- STORE_PTR(pkt, bgp_conf->hold_time);
- BGP_DATA(vb, AGENTX_INTEGER, pkt);
+ pkt = snmp_varbind_int(vb, size, bgp_conf->hold_time);
break;
+
case BGP_INTERNAL_KEEPALIVE_CONFIGURED:
- STORE_PTR(pkt, bgp_conf->keepalive_time);
- BGP_DATA(vb, AGENTX_INTEGER, pkt);
+ pkt = snmp_varbind_int(vb, size, bgp_conf->keepalive_time);
break;
- // finish me here
case BGP_INTERNAL_ORIGINATION_INTERVAL:
+ // (1..65535) but is not supported
+ pkt = snmp_varbind_int(vb, size, 0);
break;
+
case BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT:
+ // (1..65535) but is not supported
+ pkt = snmp_varbind_int(vb, size, 0);
break;
case BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME:
- now = current_time();
- STORE_PTR(pkt, (now - bgp_proto->last_rx_update) TO_S );
- BGP_DATA(vb, AGENTX_GAUGE_32, pkt);
+ pkt = snmp_varbind_gauge32(vb, size, (current_time()
+ - bgp_proto->last_rx_update) TO_S);
break;
case BGP_INTERNAL_END:
break;
}
+ if (!pkt)
+ {
+ vb->type = AGENTX_NO_SUCH_INSTANCE;
+ return ((byte *) vb) + snmp_varbind_header_size(vb);
+ }
+
return pkt;
}
+
static byte *
bgp_fill_static(struct snmp_proto *p, struct agentx_varbind *vb, byte *pkt, uint size
UNUSED, uint contid UNUSED, int byte_ord UNUSED, u8 state)
{
snmp_log("snmp bgp_fill_static ()\n");
byte *temp = pkt;
+ snmp_log("bgp_fill_static: vb->type %u, ptk %02x", vb->type, *((u32 *) pkt));
struct oid *oid = &vb->name;
+ snmp_oid_dump(oid);
+ snmp_log("bgp_fill_static");
/* snmp_bgp_state() check only prefix. To be sure on oid equivalence we need to
* compare the oid->n_subid length. All BGP static fields have same n_subid.
*/
- if (oid->n_subid != 3)
+ if (oid_state_compare(oid, state) < 0 || state == BGP_INTERNAL_END)
{
vb->type = AGENTX_NO_SUCH_OBJECT;
- return pkt;
+ return ((byte *) vb) + snmp_varbind_header_size(vb);
+ }
+ else if (oid_state_compare(oid, state) > 0)
+ {
+ vb->type = AGENTX_NO_SUCH_INSTANCE;
+ return ((byte *) vb) + snmp_varbind_header_size(vb);
}
switch (state)
{
case BGP_INTERNAL_VERSION:
- STORE_PTR(pkt, 1); /* store string len */
- pkt += 4;
- STORE_PTR(pkt, BGP4_VERSIONS);
-
- /* real size is 8 but we already shifted the pkt by 4 */
- BGP_DATA(vb, AGENTX_OCTET_STRING, pkt);
+ pkt = snmp_varbind_nstr(vb, size, BGP4_VERSIONS, 1);
break;
case BGP_INTERNAL_LOCAL_AS:
- // XXX local as to use
-
- STORE_PTR(pkt, p->local_as);
- BGP_DATA(vb, AGENTX_INTEGER, pkt);
+ pkt = snmp_varbind_int(vb, size, p->local_as);
break;
case BGP_INTERNAL_BGP:
+ default:
vb->type = AGENTX_NO_SUCH_OBJECT;
+ pkt = ((byte *) vb) + snmp_varbind_header_size(vb);
+ break;
}
+ snmp_log("bgp_fill_static: type %u packet %p", vb->type, pkt);
+ snmp_oid_dump(oid);
+
snmp_log("snmp ended with non empty pkt %u starting from %p to %p\n", pkt -
temp, temp, pkt);
+ snmp_dump_packet(temp, pkt - temp);
return pkt;
}
-byte *
-snmp_bgp_fill(struct snmp_proto *p, struct agentx_varbind *vb, byte *buf UNUSED,
-uint size UNUSED, uint contid UNUSED, int byte_ord UNUSED)
+void
+snmp_bgp_fill(struct snmp_proto *p, struct agentx_varbind *vb,
+ struct snmp_pdu_context *c)
{
u8 state = snmp_bgp_state(&vb->name);
- //snmp_log("snmp_bgp_fill() state %u is dynamic %s has value %s", state, is_dynamic(state) ? "true" : "false", snmp_bgp_has_value(state) ? "true" : "false");
+ //byte *tmp;
+ byte *pkt;
if (!is_dynamic(state))
- return bgp_fill_static(p, vb, buf, size, contid, byte_ord, state);
+ {
+ //return bgp_fill_static(p, vb, c->buffer, c->size, c->context, c->byte_ord, state);
+ pkt = bgp_fill_static(p, vb, c->buffer, c->size, c->context, c->byte_ord, state);
+ ADVANCE(c->buffer, c->size, pkt - c->buffer);
+ return;
+ }
if (is_dynamic(state) && snmp_bgp_has_value(state))
- return bgp_fill_dynamic(p, vb, buf, size, contid, byte_ord, state);
-
- else
{
- return buf;
+ pkt = bgp_fill_dynamic(p, vb, c, state);
+ ADVANCE(c->buffer, c->size, pkt - c->buffer);
+ return;
}
- /*
+ else
{
- snmp_log("has no value");
- struct agentx_varbind *vb = snmp_create_varbind(buf, oid);
- buf += snmp_varbind_size(vb);
- vb->type = AGENTX_NO_SUCH_OBJECT;
- return buf;
+ die("snmp_bgp_fill unreachable");
+ // AGENTX_NO_SUCH_OBJECT
+ ((void) c->buffer);
+ return;
}
- */
}
+
#include "snmp_utils.h"
+int agentx_type_size(enum agentx_type t);
+
/**
* snmp_is_oid_empty - check if oid is null-valued
* @oid: object identifier to check
* Test if the oid header is full of zeroes. For @oid NULL returns 0.
*/
int
-snmp_is_oid_empty(struct oid *oid)
+snmp_is_oid_empty(const struct oid *oid)
{
if (oid != NULL)
return oid->n_subid == 0 && oid->prefix == 0 && oid->include == 0;
* @buf: packet first byte
* @pkt: first byte past packet end
*/
-size_t
-snmp_pkt_len(byte *buf, byte *pkt)
+uint
+snmp_pkt_len(byte *start, byte *end)
+{
+ snmp_log("snmp_pkt_len start 0x%p end 0x%p res %u", start, end, (end - start)
+- AGENTX_HEADER_SIZE);
+ return (end - start) - AGENTX_HEADER_SIZE;
+}
+
+/**
+ *
+ * used for copying oid to in buffer oid @dest
+ */
+void snmp_oid_copy(struct oid *dest, const struct oid *src)
+{
+ STORE_U8(dest->n_subid, src->n_subid);
+ STORE_U8(dest->prefix, src->prefix);
+ STORE_U8(dest->include, src->include);
+ STORE_U8(dest->pad, 0);
+
+ for (int i = 0; i < src->n_subid; i++)
+ STORE_U32(dest->ids[i], src->ids[i]);
+}
+
+/**
+ *
+ */
+struct oid *
+snmp_oid_duplicate(pool *pool, const struct oid *oid)
{
- return (pkt - buf) - AGENTX_HEADER_SIZE;
+ struct oid *res = mb_alloc(pool, snmp_oid_size(oid));
+ memcpy(res, oid, snmp_oid_size(oid));
+ return res;
}
/**
return mb_allocz(p->p.pool, sizeof(struct oid));
}
+size_t
+snmp_str_size_from_len(uint len)
+{
+ return 4 + BIRD_ALIGN(len, 4);
+}
+
/**
* snmp_str_size - return in packet size of supplied string
* @str: measured string
* Returned value is string length aligned to 4 byte with 32bit length
* annotation included.
*/
-size_t
+inline size_t
snmp_str_size(const char *str)
{
- return 4 + BIRD_ALIGN(strlen(str), 4);
+ return snmp_str_size_from_len(strlen(str));
}
/**
* @o: object identifier to use
*/
uint
-snmp_oid_size(struct oid *o)
+snmp_oid_size(const struct oid *o)
{
return 4 + (o->n_subid * 4);
}
return sizeof(struct oid) + n_subid * sizeof(u32);
}
+uint snmp_varbind_hdr_size_from_oid(struct oid *oid)
+{
+ return snmp_oid_size(oid) + 4;
+}
+
/**
* snmp_vb_size - measure size of varbind in bytes
* @vb: variable binding to use
*/
uint
-snmp_varbind_size(struct agentx_varbind *vb)
+snmp_varbind_header_size(struct agentx_varbind *vb)
{
- return snmp_oid_size(&vb->name) + 4;
+ return snmp_varbind_hdr_size_from_oid(&vb->name);
+}
+
+uint
+snmp_varbind_size(struct agentx_varbind *vb, int byte_ord)
+{
+ uint hdr_size = snmp_varbind_header_size(vb);
+ int s = agentx_type_size(vb->type);
+
+ if (s >= 0)
+ return hdr_size + (uint) s;
+
+ void *data = ((void *) vb) + hdr_size;
+
+ if (vb->type == AGENTX_OBJECT_ID)
+ return hdr_size + snmp_oid_size((struct oid *) data);
+
+ /*
+ * Load length of octet string
+ * (AGENTX_OCTET_STRING, AGENTX_IP_ADDRESS, AGENTX_OPAQUE)
+ */
+ return hdr_size + snmp_str_size_from_len(LOAD_PTR(data, byte_ord));
+}
+
+inline uint
+snmp_context_size(struct agentx_context *c)
+{
+ return (c && c->length) ? snmp_str_size_from_len(c->length) : 0;
}
struct agentx_varbind *
snmp_create_varbind(byte *buf, struct oid *oid)
{
struct agentx_varbind *vb = (void*) buf;
+ vb->pad = 0;
memcpy(&vb->name, oid, snmp_oid_size(oid));
return vb;
}
-byte *snmp_fix_varbind(struct agentx_varbind *vb, struct oid *new)
+byte *
+snmp_fix_varbind(struct agentx_varbind *vb, struct oid *new)
{
memcpy(&vb->name, new, snmp_oid_size(new));
- return (void *) vb + snmp_varbind_size(vb);
+ return (void *) vb + snmp_varbind_header_size(vb);
}
/**
* @start: index of first address id
*/
int
-snmp_valid_ip4_index(struct oid *o, uint start)
+snmp_valid_ip4_index(const struct oid *o, uint start)
{
if (start + 3 < o->n_subid)
return snmp_valid_ip4_index_unsafe(o, start);
* length sufficiency is done.
*/
int
-snmp_valid_ip4_index_unsafe(struct oid *o, uint start)
+snmp_valid_ip4_index_unsafe(const struct oid *o, uint start)
{
for (int i = 0; i < 4; i++)
if (o->ids[start + i] >= 256)
return 1; // true
}
+byte *
+snmp_put_nstr(byte *buf, const char *str, uint len)
+{
+ uint alen = BIRD_ALIGN(len, 4);
+
+ // TODO check for '\0' in the str bytes?
+ STORE_PTR(buf, len);
+ buf += 4;
+ memcpy(buf, str, len);
+
+ /* Insert zero padding in the gap at the end */
+ for (uint i = 0; i < alen - len; i++)
+ buf[len + i] = 0x00;
+
+ return buf + alen;
+}
+
/**
* snmp_put_str - put string into SNMP PDU transcieve buffer
* @buf: pointer to first unoccupied buffer byte
snmp_put_str(byte *buf, const char *str)
{
uint len = strlen(str);
- uint slen = BIRD_ALIGN(len, 4);
-
- if (len > MAX_STR)
- return NULL;
-
- STORE_PTR(buf, len);
-
- memcpy(buf + 4, str, len);
-
- for (uint i = 0; i < slen - len; i++)
- buf[len + i] = 0x00; // PADDING
-
- return buf + snmp_str_size(str);
+ return snmp_put_nstr(buf, str, len);
}
byte *
-snmp_put_ip4(byte *buf, ip_addr addr)
+snmp_put_ip4(byte *buf, ip4_addr addr)
{
/* octet string has size 4 bytes */
STORE_PTR(buf, 4);
- put_u32(buf+4, ipa_to_u32(addr));
+ put_u32(buf+4, ip4_to_u32(addr));
return buf + 8;
}
snmp_oid_ip4_index(struct oid *o, uint start, ip4_addr addr)
{
u32 temp = ip4_to_u32(addr);
- STORE(o->ids[start], temp >> 24);
- STORE(o->ids[start + 1], (temp >> 16) & 0xFF);
- STORE(o->ids[start + 2], (temp >> 8) & 0xFF);
- STORE(o->ids[start + 3], temp & 0xFF);
+ STORE_U32(o->ids[start], temp >> 24);
+ STORE_U32(o->ids[start + 1], (temp >> 16) & 0xFF);
+ STORE_U32(o->ids[start + 2], (temp >> 8) & 0xFF);
+ STORE_U32(o->ids[start + 3], temp & 0xFF);
}
void snmp_oid_dump(struct oid *oid)
* and 1 otherwise
*/
int
-snmp_oid_compare(struct oid *left, struct oid *right)
+snmp_oid_compare(const struct oid *left, const struct oid *right)
{
const u32 INTERNET_PREFIX[] = {1, 3, 6, 1};
snmp_log("pkt [%d] 0x%02x%02x%02x%02x", i, pkt[i],pkt[i+1],pkt[i+2],pkt[i+3]);
snmp_log("end dump");
}
+
+/*
+ * Returns length of agentx_type @type in bytes.
+ * Variable length types result in -1.
+ */
+int
+agentx_type_size(enum agentx_type type)
+{
+ /*
+ * AGENTX_NULL, AGENTX_NO_SUCH_OBJECT, AGENTX_NO_SUCH_INSTANCE,
+ * AGENTX_END_OF_MIB_VIEW
+ */
+ if (type >= AGENTX_NO_SUCH_OBJECT || type == AGENTX_NULL)
+ return 0;
+
+ /* AGENTX_INTEGER, AGENTX_COUNTER_32, AGENTX_GAUGE_32, AGENTX_TIME_TICKS */
+ if (type >= AGENTX_COUNTER_32 && type <= AGENTX_TIME_TICKS ||
+ type == AGENTX_INTEGER)
+ return 4;
+
+ /* AGENTX_COUNTER_64 */
+ if (type == AGENTX_COUNTER_64)
+ return 8;
+
+ /* AGENTX_OBJECT_ID, AGENTX_OCTET_STRING, AGENTX_IP_ADDRESS, AGENTX_OPAQUE */
+ else
+ return -1;
+}
+
+static inline byte *
+snmp_varbind_type32(struct agentx_varbind *vb, uint size, enum agentx_type type, u32 val)
+{
+ ASSUME(agentx_type_size(type) == 4); /* type has 4B representation */
+
+ if (size < (uint) agentx_type_size(type))
+ {
+ snmp_log("varbind type32 returned NULL");
+ return NULL;
+ }
+
+ vb->type = type;
+ u32 *data = SNMP_VB_DATA(vb);
+ snmp_log("varbind type32 vb data 0x%p (from vb 0x%p)", data, (void *) vb);
+ *data = val;
+ return (byte *)(data + 1);
+}
+
+inline byte *
+snmp_varbind_int(struct agentx_varbind *vb, uint size, u32 val)
+{
+ return snmp_varbind_type32(vb, size, AGENTX_INTEGER, val);
+}
+
+
+inline byte *
+snmp_varbind_counter32(struct agentx_varbind *vb, uint size, u32 val)
+{
+ return snmp_varbind_type32(vb, size, AGENTX_COUNTER_32, val);
+}
+
+inline byte *
+snmp_varbind_gauge32(struct agentx_varbind *vb, uint size, s64 val)
+{
+ return snmp_varbind_type32(vb, size, AGENTX_GAUGE_32,
+ MAX(0, MIN(val, UINT32_MAX)));
+}
+
+inline byte *
+snmp_varbind_ip4(struct agentx_varbind *vb, uint size, ip4_addr addr)
+{
+ if (size < snmp_str_size_from_len(4))
+ {
+ snmp_log("varbind ip4 NULL");
+ return NULL;
+ }
+
+ vb->type = AGENTX_IP_ADDRESS;
+ snmp_log("snmp_varbind_ip4 vb data 0x%p (from vb 0x%p)", SNMP_VB_DATA(vb), (void
+*) vb);
+ return snmp_put_ip4(SNMP_VB_DATA(vb), addr);
+}
+
+inline byte *
+snmp_varbind_nstr(struct agentx_varbind *vb, uint size, const char *str, uint len)
+{
+ if (size < snmp_str_size_from_len(len))
+ {
+ snmp_log("varbind nstr NULL");
+ return NULL;
+ }
+
+ vb->type = AGENTX_OCTET_STRING;
+ //die("snmp_varbind_nstr() %p.data = %p", vb, SNMP_VB_DATA(vb));
+ snmp_log("snmp_varbind_nstr vb data 0x%p (from vb 0x%p)", SNMP_VB_DATA(vb), (void *) vb);
+ //snmp_log("snmp_varbind_nstr() %p.data = %p", vb, SNMP_VB_DATA(vb));
+ return snmp_put_nstr(SNMP_VB_DATA(vb), str, len);
+}
+
+inline enum agentx_type
+snmp_search_res_to_type(enum snmp_search_res r)
+{
+ ASSUME(r != SNMP_SEARCH_OK);
+ static enum agentx_type type_arr[] = {
+ [SNMP_SEARCH_NO_OBJECT] = AGENTX_NO_SUCH_OBJECT,
+ [SNMP_SEARCH_NO_INSTANCE] = AGENTX_NO_SUCH_INSTANCE,
+ [SNMP_SEARCH_END_OF_VIEW] = AGENTX_END_OF_MIB_VIEW,
+ };
+
+ return type_arr[r];
+}