From 8a1f2dba66fbe0100222c5be2e6b5c4e2e8f3075 Mon Sep 17 00:00:00 2001 From: Vojtech Vilimek Date: Mon, 4 Sep 2023 13:53:45 +0200 Subject: [PATCH] SNMP: BGP4-MIB notifications --- proto/snmp/bgp_mib.c | 97 ++++++++++++++++++++++++++++++++++++++++--- proto/snmp/bgp_mib.h | 3 ++ proto/snmp/subagent.c | 63 +--------------------------- proto/snmp/subagent.h | 2 + 4 files changed, 99 insertions(+), 66 deletions(-) diff --git a/proto/snmp/bgp_mib.c b/proto/snmp/bgp_mib.c index 093b329f..464fcf32 100644 --- a/proto/snmp/bgp_mib.c +++ b/proto/snmp/bgp_mib.c @@ -49,6 +49,73 @@ static const char * const debug_bgp_states[] UNUSED = { [BGP_INTERNAL_NO_VALUE] = "BGP_INTERNAL_NO_VALUE", }; +static void +snmp_bgp_notify_common(struct snmp_proto *p, uint type, ip4_addr ip4, char last_error[], uint state_val) +{ + // TODO remove heap allocation, put the data on stack + +#define SNMP_OID_SIZE_FROM_LEN(x) (sizeof(struct oid) + (x) * sizeof(u32)) + + /* trap OID bgpEstablishedNotification (.1.3.6.1.2.1.0.1) */ + struct oid *head = mb_alloc(p->p.pool, SNMP_OID_SIZE_FROM_LEN(3)); + head->n_subid = 3; + head->prefix = 2; + head->include = head->pad = 0; + + u32 trap_ids[] = { 1, 0, type }; + for (uint i = 0; i < head->n_subid; i++) + head->ids[i] = trap_ids[i]; + + /* OIDs, VB type headers, octet string, ip4 address, integer */ + uint sz = 3 * SNMP_OID_SIZE_FROM_LEN(9) + 3 * 4 + 8 + 8 + 4; + + /* Paylaod OIDs */ + + void *data = mb_alloc(p->p.pool, sz); + struct agentx_varbind *addr_vb = data; + /* +4 for varbind header, +8 for octet string */ + struct agentx_varbind *error_vb = data + SNMP_OID_SIZE_FROM_LEN(9) + 4 + 8; + struct agentx_varbind *state_vb = (void *) error_vb + SNMP_OID_SIZE_FROM_LEN(9) + 4 + 8; + + addr_vb->pad = error_vb->pad = state_vb->pad = 0; + + struct oid *addr = &addr_vb->name; + struct oid *error = &error_vb->name; + struct oid *state = &state_vb->name; + + addr->n_subid = error->n_subid = state->n_subid = 9; + addr->prefix = error->prefix = state->prefix = 2; + addr->include = error->include = state->include = 0; + addr->pad = error->pad = state->pad = 0; + + u32 oid_ids[] = { + SNMP_MIB_2, SNMP_BGP4_MIB, SNMP_BGP_PEER_TABLE, SNMP_BGP_PEER_ENTRY + }; + + for (uint i = 0; i < sizeof(oid_ids) / sizeof(oid_ids[0]); i++) + addr->ids[i] = error->ids[i] = state->ids[i] = oid_ids[i]; + + addr->ids[4] = SNMP_BGP_REMOTE_ADDR; + error->ids[4] = SNMP_BGP_LAST_ERROR; + state->ids[4] = SNMP_BGP_STATE; + + for (uint i = 0; i < 4; i++) + addr->ids[5 + i] = error->ids[5 + i] = state->ids[5 + i] \ + = (ip4_to_u32(ip4) >> (8 * (3-i))) & 0xFF; + + snmp_varbind_ip4(addr_vb, 100, ip4); + + snmp_varbind_nstr(error_vb, 100, last_error, 2); + + snmp_varbind_int(state_vb, 100, state_val); + + snmp_notify_pdu(p, head, data, sz, 0); + mb_free(head); + mb_free(data); + +#undef SNMP_OID_SIZE_FROM_LEN +} + static inline uint snmp_bgp_fsm_state(struct bgp_proto *bgp_proto) { @@ -68,6 +135,29 @@ snmp_bgp_fsm_state(struct bgp_proto *bgp_proto) return MAX(bgp_in->state, bgp_out->state); } +static void +snmp_bgp_notify_wrapper(struct snmp_proto *p, struct bgp_proto *bgp, uint type) +{ + // possibly dangerous + ip4_addr ip4 = ipa_to_ip4(bgp->remote_ip); + char last_error[2] = SNMP_BGP_LAST_ERROR(bgp); + uint state_val = snmp_bgp_fsm_state(bgp); + snmp_bgp_notify_common(p, type, ip4, last_error, state_val); +} + +void +snmp_bgp_notify_established(struct snmp_proto *p, struct bgp_proto *bgp) +{ + /* .1.3.6.1.2.15.0.>1< i.e. BGP4-MIB::bgpEstablishedNotification */ + snmp_bgp_notify_wrapper(p, bgp, 1); +} + +void +snmp_bgp_notify_backward_trans(struct snmp_proto *p, struct bgp_proto *bgp) +{ + /* .1.3.6.1.2.15.0.>2< i.e. BGP4-MIB::bgpBackwardTransNotification */ + snmp_bgp_notify_wrapper(p, bgp, 2); +} void snmp_bgp_register(struct snmp_proto *p) @@ -894,11 +984,8 @@ bgp_fill_dynamic(struct snmp_proto UNUSED *p, struct agentx_varbind *vb, return ((byte *) vb) + snmp_varbind_header_size(vb); } - struct bgp_conn *bgp_conn = bgp_proto->conn; - struct bgp_conn *bgp_in = &bgp_proto->incoming_conn; - struct bgp_conn *bgp_out = &bgp_proto->outgoing_conn; - - 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 bgp_state = snmp_bgp_fsm_state(bgp_proto); diff --git a/proto/snmp/bgp_mib.h b/proto/snmp/bgp_mib.h index 1bca891f..d2223498 100644 --- a/proto/snmp/bgp_mib.h +++ b/proto/snmp/bgp_mib.h @@ -47,6 +47,9 @@ struct oid *snmp_bgp_search(struct snmp_proto *p, struct oid *o_start, struct oi enum snmp_search_res snmp_bgp_search2(struct snmp_proto *p, struct oid **searched, const struct oid *o_end, uint contid); void snmp_bgp_fill(struct snmp_proto *p, struct agentx_varbind *vb, struct snmp_pdu_context *c); +void snmp_bgp_notify_established(struct snmp_proto *p, struct bgp_proto *bgp); +void snmp_bgp_notify_backward_trans(struct snmp_proto *p, struct bgp_proto *bgp); + #define SNMP_BGP_VERSION 1 #define SNMP_BGP_LOCAL_AS 2 #define SNMP_BGP_PEER_TABLE 3 diff --git a/proto/snmp/subagent.c b/proto/snmp/subagent.c index 66ebb469..5f6acf1a 100644 --- a/proto/snmp/subagent.c +++ b/proto/snmp/subagent.c @@ -36,7 +36,6 @@ static struct agentx_response *prepare_response(struct snmp_proto *p, struct snm static void response_err_ind(struct agentx_response *res, uint err, uint ind); static uint update_packet_size(struct snmp_proto *p, byte *start, byte *end); static struct oid *search_mib(struct snmp_proto *p, const struct oid *o_start, const struct oid *o_end, struct oid *o_curr, struct snmp_pdu_context *c, enum snmp_search_res *result); -static void notify_pdu(struct snmp_proto *p, struct oid *oid, void *opaque, uint size, int include_uptime); u32 snmp_internet[] = { SNMP_ISO, SNMP_ORG, SNMP_DOD, SNMP_INTERNET }; @@ -122,8 +121,8 @@ open_pdu(struct snmp_proto *p, struct oid *oid) snmp_log("sk_send error"); } -static void -notify_pdu(struct snmp_proto *p, struct oid *oid, void *opaque, uint size, int include_uptime) +void +snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *opaque, uint size, int include_uptime) { sock *sk = p->sock; @@ -1227,64 +1226,6 @@ snmp_rx(sock *sk, uint size) void snmp_ping(struct snmp_proto *p) { - { -#define SNMP_OID_SIZE_FROM_LEN(x) (sizeof(struct oid) + (x) * sizeof(u32)) - /* trap OID bgpEstablishedNotification (.1.3.6.1.2.1.0.1) */ - struct oid *head = mb_alloc(p->p.pool, SNMP_OID_SIZE_FROM_LEN(3)); - head->n_subid = 3; - head->prefix = 2; - head->include = head->pad = 0; - - u32 trap_ids[] = { 1, 0, 1 }; - for (uint i = 0; i < head->n_subid; i++) - head->ids[i] = trap_ids[i]; - - /* paylaod oids */ - uint sz = 3 * SNMP_OID_SIZE_FROM_LEN(9) + 3 * 4 + 2 * 8 + 4 - 20; - void *data = mb_alloc(p->p.pool, sz); - struct agentx_varbind *addr_vb = data; - /* +4 for varbind header, +8 for octet string */ - struct agentx_varbind *error_vb = data + SNMP_OID_SIZE_FROM_LEN(9) + 4 + 8; - struct agentx_varbind *state_vb = (void *) error_vb + SNMP_OID_SIZE_FROM_LEN(9) + 4 + 8; -#undef SNMP_OID_SIZE_FROM_LEN - - addr_vb->pad = error_vb->pad = state_vb->pad = 0; - - struct oid *addr = &addr_vb->name; - struct oid *error = &error_vb->name; - struct oid *state = &state_vb->name; - - addr->n_subid = error->n_subid = state->n_subid = 9; - addr->prefix = error->prefix = state->prefix = 2; - addr->include = error->include = state->include = 0; - addr->pad = error->pad = state->pad = 0; - - u32 oid_ids[] = { - SNMP_MIB_2, SNMP_BGP4_MIB, SNMP_BGP_PEER_TABLE, SNMP_BGP_PEER_ENTRY, 0, - 10, 1, 2, 1 - }; - for (uint i = 0; i < addr->n_subid; i++) - addr->ids[i] = error->ids[i] = state->ids[i] = oid_ids[i]; - - addr->ids[4] = SNMP_BGP_REMOTE_ADDR; - error->ids[4] = SNMP_BGP_LAST_ERROR; - state->ids[4] = SNMP_BGP_STATE; - - ip4_addr ip4 = ip4_build(10,1,2,1); - snmp_varbind_ip4(addr_vb, 100, ip4); - - char error_str[] = { 0, 0 }; - snmp_varbind_nstr(error_vb, 100, error_str, 2); - - snmp_varbind_int(state_vb, 100, 6); - - u32 now = current_time() TO_S; - if (now % 4 == 0) - notify_pdu(p, head, data, sz, 1); - else if (now % 2 == 0) - notify_pdu(p, head, data, sz, 0); - } - sock *sk = p->sock; snmp_dump_packet(sk->tpos, AGENTX_HEADER_SIZE + 4); snmp_log("snmp_ping sk->tpos 0x%p", sk->tpos); diff --git a/proto/snmp/subagent.h b/proto/snmp/subagent.h index 57e1f5eb..d23d2d8e 100644 --- a/proto/snmp/subagent.h +++ b/proto/snmp/subagent.h @@ -322,6 +322,8 @@ 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); +void snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *opaque, uint size, int include_uptime); + // debug wrapper #define snmp_log(...) log(L_INFO "snmp " __VA_ARGS__)