0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2025-03-11 17:08:46 +00:00

changes in bgp_mib.c API (mainly)

This commit is contained in:
Vojtech Vilimek 2023-07-26 14:02:23 +02:00
parent ec7d4fd52c
commit 9f8950d4d7
5 changed files with 763 additions and 244 deletions

View File

@ -194,17 +194,23 @@ bgp_get_candidate(u32 field)
/* 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
@ -283,6 +289,9 @@ snmp_bgp_state(struct oid *oid)
* -> BGP4-MIB::bgp (root)
*/
if (snmp_is_oid_empty(oid))
return BGP_INTERNAL_END;
u8 state = BGP_INTERNAL_NO_VALUE;
u8 candidate;
@ -374,15 +383,10 @@ snmp_bgp_has_value(u8 state)
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;
}
/**
@ -423,15 +427,8 @@ snmp_bgp_next_state(u8 state)
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:
@ -445,20 +442,19 @@ snmp_bgp_is_supported(struct oid *o)
/* 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
@ -468,50 +464,127 @@ snmp_bgp_is_supported(struct oid *o)
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)
@ -559,6 +632,9 @@ update_bgp_oid(struct oid *oid, u8 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;
@ -567,37 +643,50 @@ update_bgp_oid(struct oid *oid, u8 state)
// 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");
@ -605,10 +694,7 @@ bgp_find_dynamic_oid(struct snmp_proto *p, struct oid *o_start, struct oid *o_en
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;
}
@ -616,9 +702,7 @@ bgp_find_dynamic_oid(struct snmp_proto *p, struct oid *o_start, struct oid *o_en
// 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
}
@ -626,8 +710,6 @@ bgp_find_dynamic_oid(struct snmp_proto *p, struct oid *o_start, struct oid *o_en
else
{
snmp_log("trie_walk_next() returned false, cleaning");
mb_free(net);
mb_free(ws);
}
return NULL;
@ -652,6 +734,9 @@ UNUSED, u8 current_state)
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);
@ -659,9 +744,208 @@ UNUSED, u8 current_state)
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);
@ -674,14 +958,14 @@ search_bgp_mib(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, uin
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);
}
@ -728,19 +1012,21 @@ search_bgp_mib(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, uin
}
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;
}
@ -754,25 +1040,23 @@ UNUSED, uint contid UNUSED, int byte_ord UNUSED, u8 state)
{
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;
@ -794,164 +1078,129 @@ UNUSED, uint contid UNUSED, int byte_ord UNUSED, u8 state)
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);
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->hold_time);
break;
// finish me here
case BGP_INTERNAL_ORIGINATION_INTERVAL:
case BGP_INTERNAL_KEEPALIVE_CONFIGURED:
pkt = snmp_varbind_int(vb, size, bgp_conf->keepalive_time);
break;
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:
@ -970,78 +1219,96 @@ UNUSED, uint contid UNUSED, int byte_ord UNUSED, u8 state)
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);
{
pkt = bgp_fill_dynamic(p, vb, c, state);
ADVANCE(c->buffer, c->size, pkt - c->buffer);
return;
}
else
{
return buf;
die("snmp_bgp_fill unreachable");
// AGENTX_NO_SUCH_OBJECT
((void) c->buffer);
return;
}
/*
{
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;
}
*/
}

View File

@ -32,6 +32,10 @@ enum BGP4_MIB {
SNMP_BGP_IN_UPDATE_ELAPSED_TIME = 24, /* UNSUPPORTED */
} PACKED;
/* version of BGP, here BGP-4 */
#define SNMP_BGP_NEGOTIATED_VER_VALUE 4
#define SNMP_BGP_NEGOTIATED_VER_NO_VALUE 0
//void snmp_init_bgp_table(void);
//void snmp_del_bgp_table(void);
@ -45,8 +49,10 @@ u8 snmp_bgp_state(struct oid *o);
u8 snmp_bgp_get_valid(u8 state);
u8 snmp_bgp_getnext_valid(u8 state);
struct oid *search_bgp_mib(struct snmp_proto *p , struct oid *o_start, struct oid *o_end, uint contid);
byte * snmp_bgp_fill(struct snmp_proto *p, struct agentx_varbind *vb, byte *buf, uint size, uint contid UNUSED, int byte_ord);
struct oid *snmp_bgp_search(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, uint contid);
enum snmp_search_res snmp_bgp_search2(struct snmp_proto *p, struct oid **searched, const struct oid *o_end, uint contid);
//byte * snmp_bgp_fill(struct snmp_proto *p, struct agentx_varbind *vb, byte *buf, uint size, uint contid UNUSED, int byte_ord);
void snmp_bgp_fill(struct snmp_proto *p, struct agentx_varbind *vb, struct snmp_pdu_context *c);
#define BGP4_MIB_VERSION 1
#define BGP4_MIB_LOCAL_AS 2

View File

@ -10,6 +10,8 @@
#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
@ -17,7 +19,7 @@
* 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;
@ -30,10 +32,38 @@ snmp_is_oid_empty(struct oid *oid)
* @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)
{
return (pkt - buf) - AGENTX_HEADER_SIZE;
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)
{
struct oid *res = mb_alloc(pool, snmp_oid_size(oid));
memcpy(res, oid, snmp_oid_size(oid));
return res;
}
/**
@ -46,6 +76,12 @@ snmp_oid_blank(struct snmp_proto *p)
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
@ -53,10 +89,10 @@ snmp_oid_blank(struct snmp_proto *p)
* 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));
}
/**
@ -64,7 +100,7 @@ snmp_str_size(const char *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);
}
@ -79,28 +115,62 @@ snmp_oid_sizeof(uint n_subid)
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);
}
/**
@ -109,7 +179,7 @@ byte *snmp_fix_varbind(struct agentx_varbind *vb, struct oid *new)
* @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);
@ -126,7 +196,7 @@ snmp_valid_ip4_index(struct oid *o, uint 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)
@ -135,6 +205,23 @@ snmp_valid_ip4_index_unsafe(struct oid *o, uint start)
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
@ -148,28 +235,16 @@ 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;
}
@ -231,10 +306,10 @@ void
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)
@ -278,7 +353,7 @@ 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};
@ -404,3 +479,113 @@ snmp_dump_packet(byte *pkt, uint size)
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];
}

View File

@ -3,30 +3,38 @@
#include "subagent.h"
size_t snmp_pkt_len(byte *buf, byte *pkt);
uint snmp_pkt_len(byte *start, byte *end);
size_t snmp_str_size_from_len(uint len);
size_t snmp_str_size(const char *str);
int snmp_is_oid_empty(struct oid *oid);
int snmp_valid_ip4_index(struct oid *o, uint start);
int snmp_valid_ip4_index_unsafe(struct oid *o, uint start);
uint snmp_oid_size(struct oid *o);
int snmp_is_oid_empty(const struct oid *oid);
int snmp_valid_ip4_index(const struct oid *o, uint start);
int snmp_valid_ip4_index_unsafe(const struct oid *o, uint start);
uint snmp_oid_size(const struct oid *o);
size_t snmp_oid_sizeof(uint n_subid);
uint snmp_varbind_size(struct agentx_varbind *vb);
uint snmp_varbind_hdr_size_from_oid(struct oid *oid);
uint snmp_varbind_header_size(struct agentx_varbind *vb);
uint snmp_varbind_size(struct agentx_varbind *vb, int byte_ord);
uint snmp_context_size(struct agentx_context *c);
void snmp_oid_copy(struct oid *dest, const struct oid *src);
struct oid *snmp_oid_duplicate(pool *pool, const struct oid *oid);
struct oid *snmp_oid_blank(struct snmp_proto *p);
struct agentx_varbind *snmp_create_varbind(byte* buf, struct oid *oid);
byte *snmp_fix_varbind(struct agentx_varbind *vb, struct oid *new);
int snmp_oid_compare(struct oid *first, struct oid *second);
int snmp_oid_compare(const struct oid *first, const struct oid *second);
byte *snmp_no_such_object(byte *buf, struct agentx_varbind *vb, struct oid *oid);
byte *snmp_no_such_instance(byte *buf, struct agentx_varbind *vb, struct oid *oid);
byte *snmp_put_str(byte *buf, const char *str);
byte *snmp_put_nstr(byte *buf, const char *str, uint len);
byte *snmp_put_blank(byte *buf);
byte *snmp_put_oid(byte *buf, struct oid *oid);
byte *snmp_put_ip4(byte *buf, ip_addr ip4);
byte *snmp_put_ip4(byte *buf, ip4_addr ip4);
byte *snmp_put_fbyte(byte *buf, u8 data);
@ -34,13 +42,19 @@ void snmp_oid_ip4_index(struct oid *o, uint start, ip4_addr addr);
void snmp_oid_dump(struct oid *oid);
int snmp_oid_compare(struct oid *left, struct oid *right);
struct oid *snmp_prefixize(struct snmp_proto *p, struct oid *o, int byte_ord);
//struct oid *snmp_prefixize(struct snmp_proto *p, struct oid *o, int byte_ord);
struct snmp_register *snmp_register_create(struct snmp_proto *p, u8 mib_class);
void snmp_register_ack(struct snmp_proto *p, struct agentx_header *h);
byte *snmp_varbind_int(struct agentx_varbind *vb, uint size, u32 val);
byte *snmp_varbind_counter32(struct agentx_varbind *vb, uint size, u32 val);
byte *snmp_varbind_gauge32(struct agentx_varbind *vb, uint size, s64 val);
byte *snmp_varbind_ip4(struct agentx_varbind *vb, uint size, ip4_addr addr);
byte *snmp_varbind_nstr(struct agentx_varbind *vb, uint size, const char *str, uint len);
void snmp_dump_packet(byte *pkt, uint size);
enum agentx_type snmp_search_res_to_type(enum snmp_search_res res);
#endif

View File

@ -26,7 +26,7 @@ enum SNMP_CLASSES {
SNMP_CLASS_END,
};
#define BGP4_VERSIONS 0x10
#define BGP4_VERSIONS ((char[]) { 0x10 })
enum agentx_type {
AGENTX_INTEGER = 2,
@ -44,6 +44,13 @@ enum agentx_type {
AGENTX_END_OF_MIB_VIEW = 130,
} PACKED;
enum snmp_search_res {
SNMP_SEARCH_OK = 0,
SNMP_SEARCH_NO_OBJECT = 1,
SNMP_SEARCH_NO_INSTANCE = 2,
SNMP_SEARCH_END_OF_VIEW = 3,
};
#define AGENTX_ADMIN_STOP 1
#define AGENTX_ADMIN_START 2
@ -53,18 +60,15 @@ enum agentx_type {
#define SNMP_NATIVE
#ifdef SNMP_NATIVE
#define STORE(v,c) (v) = (u32) (c)
#define STORE_16(v,c) (v) = (u16) (c)
#define STORE_PTR(v,c) *((u32 *) (v)) = (u32) (c)
#define SNMP_UPDATE(h,l) \
STORE((h)->payload, l)
#define STORE_U32(dest, val) ((dest) = (u32) (val))
#define STORE_U16(dest, val) ((dest) = (u16) (val))
#define STORE_U8(dest, val) ((dest) = (u8) (val))
#define STORE_PTR(ptr, val) (*((u32 *) (ptr)) = (u32) (val))
#else
#define STORE(v, c) put_u32(&v, c)
#define STORE_16(v,c) put_u32(&v, c)
#define STORE_PTR(v,c) put_u32(v, c)
#define SNMP_UPDATE(h,l) \
STORE(h->payload, l)
#define STORE_U32(dest, val) put_u32(&(dest), (val))
#define STORE_U16(dest, val) put_u16(&(dest), (val))
#define STORE_U8(dest, val) put_u8(&(dest), (val))
#define STORE_PTR(ptr, val) put_u32(ptr, val)
#endif
/* storing byte (u8) is always the same */
@ -82,18 +86,18 @@ enum agentx_type {
#endif
#define SNMP_B_HEADER(h, t) SNMP_HEADER(h, t, AGENTX_FLAG_BLANK)
#define SNMP_SESSION(h, p) \
STORE(h->session_id, p->session_id); \
STORE(h->transaction_id, p->transaction_id); \
p->transaction_id++; \
STORE(h->packet_id, p->packet_id);
#define SNMP_BLANK_HEADER(h, t) SNMP_HEADER(h, t, AGENTX_FLAG_BLANK)
#define SNMP_CREATE(b, t, n) \
n = (void *) (b); \
memset(n, 0, sizeof(t)); \
(b) += sizeof(t);
#define SNMP_SESSION(h, p) \
STORE_U32(h->session_id, p->session_id); \
STORE_U32(h->transaction_id, p->transaction_id); \
STORE_U32(h->packet_id, p->packet_id)
#define LOAD(v, bo) ((bo) ? get_u32(&v) : (u32) (v))
#define LOAD_16(v, bo) ((bo) ? get_u16(&v) : (u16) (v))
#define LOAD_PTR(v, bo) ((bo) ? get_u32(v) : (u32) *(v))
@ -125,7 +129,17 @@ enum agentx_type {
(varbind)->type = type_; \
packet += offset;
#define BGP_DATA(varbind, type_, packet) BGP_DATA_(varbind, type_, packet, 4)
#define SNMP_PUT_OID(buf, size, oid, byte_ord) \
({ \
struct agentx_varbind *vb = (void *) buf; \
SNMP_FILL_VARBIND(vb, oid, byte_ord); \
})
#define SNMP_FILL_VARBIND(vb, oid, byte_ord) \
snmp_oid_copy(&(vb)->name, (oid), (byte_ord)), snmp_oid_size((oid))
#define SNMP_VB_DATA(varbind) \
(((void *)(varbind)) + snmp_varbind_header_size(varbind))
struct agentx_header {
u8 version;
@ -273,12 +287,45 @@ enum agentx_response_err {
AGENTX_RES_PROCESSING_ERR = 268,
} PACKED;
struct agentx_context {
char *context; /* string name of this context */
uint length; /* normal strlen() size */
/* add buffered context hash? */
};
struct snmp_pdu_context {
byte *buffer; /* pointer to buffer */
uint size; /* unused space in buffer */
uint context; /* context hash */
int byte_ord; /* flag signaling NETWORK_BYTE_ORDER */
enum agentx_response_err error; /* storage for result of current action */
};
struct agentx_alloc_context {
u8 is_instance; /* flag INSTANCE_REGISTRATION */
u8 new_index; /* flag NEW_INDEX */
u8 any_index; /* flag ANY_INDEX */
char *context; /* context to allocate in */
uint clen; /* length of context string */
};
struct additional_buffer {
node n;
byte *buf; /* pointer to buffer data */
byte *pos; /* position of first unused byte */
};
int snmp_rx(sock *sk, uint size);
int snmp_rx_stop(sock *sk, uint size);
void snmp_down(struct snmp_proto *p);
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);
void snmp_manage_tbuf(struct snmp_proto *p, struct snmp_pdu_context *c);
struct oid *snmp_prefixize(struct snmp_proto *p, const struct oid *o, int byte_ord);
u8 snmp_get_mib_class(const struct oid *oid);
// debug wrapper
#define snmp_log(...) log(L_INFO "snmp " __VA_ARGS__)