diff options
author | Karen Schoener <karen@voltanet.io> | 2021-03-15 18:44:12 +0100 |
---|---|---|
committer | Karen Schoener <karen@voltanet.io> | 2021-03-16 15:23:34 +0100 |
commit | d4d6e7d87e6630944cbd5a53620ad4658c8dbf7a (patch) | |
tree | b400f0f6d05659a57b493b4314f3c634d3cdd70e /ldpd | |
parent | Merge pull request #8260 from volta-networks/fix_isis_snmp_test (diff) | |
download | frr-d4d6e7d87e6630944cbd5a53620ad4658c8dbf7a.tar.xz frr-d4d6e7d87e6630944cbd5a53620ad4658c8dbf7a.zip |
ldpd: Add support for the read-only snmp mib objects that are statistics
Add support for the read-only snmp mib objects as described in RFC 3815
that are statistics.
Signed-off-by: Lynne Morrison <lynne@voltanet.io>
Signed-off-by: Karen Schoener <karen@voltanet.io>
Diffstat (limited to 'ldpd')
-rw-r--r-- | ldpd/ldp_snmp.c | 157 | ||||
-rw-r--r-- | ldpd/ldpd.h | 19 | ||||
-rw-r--r-- | ldpd/notification.c | 79 | ||||
-rw-r--r-- | ldpd/packet.c | 10 |
4 files changed, 261 insertions, 4 deletions
diff --git a/ldpd/ldp_snmp.c b/ldpd/ldp_snmp.c index c9b37c0d2..97dde616a 100644 --- a/ldpd/ldp_snmp.c +++ b/ldpd/ldp_snmp.c @@ -374,6 +374,76 @@ static uint8_t *ldpEntityTable(struct variable *v, oid name[], size_t *length, return NULL; } +static uint8_t *ldpEntityStatsTable(struct variable *v, oid name[], + size_t *length, int exact, size_t *var_len, + WriteMethod **write_method) +{ + struct in_addr entityLdpId = {.s_addr = 0}; + int len; + + *write_method = NULL; + + if (smux_header_table(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + + if (exact) { + if (*length != LDP_ENTITY_TOTAL_LEN) + return NULL; + } else { + len = *length - v->namelen - LDP_ENTITY_MAX_IDX_LEN; + if (len > 0) + return NULL; + + entityLdpId.s_addr = ldp_rtr_id_get(leconf); + + /* Copy the name out */ + memcpy(name, v->name, v->namelen * sizeof(oid)); + + /* Append index */ + *length = LDP_ENTITY_TOTAL_LEN; + oid_copy_addr(name + v->namelen, &entityLdpId, + IN_ADDR_SIZE); + name[v->namelen + 4] = 0; + name[v->namelen + 5] = 0; + name[v->namelen + 6] = LDP_DEFAULT_ENTITY_INDEX; + } + + /* Return the current value of the variable */ + switch (v->magic) { + case MPLSLDPENTITYSTATSSESSIONATTEMPTS: + return SNMP_INTEGER(leconf->stats.session_attempts); + case MPLSLDPENTITYSTATSSESSIONREJHELLO: + return SNMP_INTEGER(leconf->stats.session_rejects_hello); + case MPLSLDPENTITYSTATSSESSIONREJAD: + return SNMP_INTEGER(leconf->stats.session_rejects_ad); + case MPLSLDPENTITYSTATSSESSIONREJMAXPDU: + return SNMP_INTEGER(leconf->stats.session_rejects_max_pdu); + case MPLSLDPENTITYSTATSSESSIONREJLR: + return SNMP_INTEGER(leconf->stats.session_rejects_lr); + case MPLSLDPENTITYSTATSBADLDPID: + return SNMP_INTEGER(leconf->stats.bad_ldp_id); + case MPLSLDPENTITYSTATSBADPDULENGTH: + return SNMP_INTEGER(leconf->stats.bad_pdu_len); + case MPLSLDPENTITYSTATSBADMSGLENGTH: + return SNMP_INTEGER(leconf->stats.bad_msg_len); + case MPLSLDPENTITYSTATSBADTLVLENGTH: + return SNMP_INTEGER(leconf->stats.bad_tlv_len); + case MPLSLDPENTITYSTATSMALFORMEDTLV: + return SNMP_INTEGER(leconf->stats.malformed_tlv); + case MPLSLDPENTITYSTATSKEEPALIVEEXP: + return SNMP_INTEGER(leconf->stats.keepalive_timer_exp); + case MPLSLDPENTITYSTATSSHUTDOWNRCVNOTIFY: + return SNMP_INTEGER(leconf->stats.shutdown_rcv_notify); + case MPLSLDPENTITYSTATSSHUTDOWNSENTNOTIFY: + return SNMP_INTEGER(leconf->stats.shutdown_send_notify); + default: + return NULL; + } + + return NULL; +} + #define LDP_ADJACENCY_ENTRY_MAX_IDX_LEN 14 static void ldpHelloAdjacencyTable_oid_to_index( @@ -863,6 +933,59 @@ static uint8_t *ldpSessionTable(struct variable *v, oid name[], size_t *length, return NULL; } +static uint8_t *ldpSessionStatsTable(struct variable *v, oid name[], + size_t *length, + int exact, size_t *var_len, + WriteMethod **write_method) +{ + struct in_addr entityLdpId = {.s_addr = 0}; + uint32_t entityIndex = 0; + struct in_addr peerLdpId = {.s_addr = 0}; + + if (smux_header_table(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + + struct ctl_nbr *ctl_nbr = ldpPeerTable_lookup(v, name, length, exact, + &entityLdpId, &entityIndex, &peerLdpId); + + if (!ctl_nbr) + return NULL; + + if (!exact) { + entityLdpId.s_addr = ldp_rtr_id_get(leconf); + entityIndex = LDP_DEFAULT_ENTITY_INDEX; + peerLdpId = ctl_nbr->id; + + /* Copy the name out */ + memcpy(name, v->name, v->namelen * sizeof(oid)); + + /* Append index */ + oid_copy_addr(name + v->namelen, &entityLdpId, + sizeof(struct in_addr)); + name[v->namelen + 4] = 0; + name[v->namelen + 5] = 0; + name[v->namelen + 6] = entityIndex; + oid_copy_addr(name + v->namelen + 7, &peerLdpId, + sizeof(struct in_addr)); + name[v->namelen + 11] = 0; + name[v->namelen + 12] = 0; + + *length = v->namelen + LDP_PEER_ENTRY_MAX_IDX_LEN; + } + + switch (v->magic) { + case MPLSLDPSESSIONSTATSUNKNOWNMESTYPEERRORS: + return SNMP_INTEGER(ctl_nbr->stats.unknown_msg); + case MPLSLDPSESSIONSTATSUNKNOWNTLVERRORS: + return SNMP_INTEGER(ctl_nbr->stats.unknown_tlv); + default: + return NULL; + } + + return NULL; +} + static struct variable ldpe_variables[] = { {MPLS_LDP_LSR_ID, STRING, RONLY, ldpLsrId, 3, {1, 1, 1}}, {MPLS_LDP_LSR_LOOP_DETECTION_CAPABLE, INTEGER, RONLY, @@ -920,6 +1043,34 @@ static struct variable ldpe_variables[] = { {MPLSLDPENTITYROWSTATUS, INTEGER, RONLY, ldpEntityTable, 5, {1, 2, 3, 1, 23}}, + /* MPLS LDP mplsLdpEntityStatsTable. */ + { MPLSLDPENTITYSTATSSESSIONATTEMPTS, COUNTER32, RONLY, + ldpEntityStatsTable, 5, {1, 2, 4, 1, 1}}, + { MPLSLDPENTITYSTATSSESSIONREJHELLO, COUNTER32, RONLY, + ldpEntityStatsTable, 5, {1, 2, 4, 1, 2}}, + { MPLSLDPENTITYSTATSSESSIONREJAD, COUNTER32, RONLY, + ldpEntityStatsTable, 5, {1, 2, 4, 1, 3}}, + { MPLSLDPENTITYSTATSSESSIONREJMAXPDU, COUNTER32, RONLY, + ldpEntityStatsTable, 5, {1, 2, 4, 1, 4}}, + { MPLSLDPENTITYSTATSSESSIONREJLR, COUNTER32, RONLY, + ldpEntityStatsTable, 5, {1, 2, 4, 1, 5}}, + { MPLSLDPENTITYSTATSBADLDPID, COUNTER32, RONLY, + ldpEntityStatsTable, 5, {1, 2, 4, 1, 6}}, + { MPLSLDPENTITYSTATSBADPDULENGTH, COUNTER32, RONLY, + ldpEntityStatsTable, 5, {1, 2, 4, 1, 7}}, + { MPLSLDPENTITYSTATSBADMSGLENGTH, COUNTER32, RONLY, + ldpEntityStatsTable, 5, {1, 2, 4, 1, 8}}, + { MPLSLDPENTITYSTATSBADTLVLENGTH, COUNTER32, RONLY, + ldpEntityStatsTable, 5, {1, 2, 4, 1, 9}}, + { MPLSLDPENTITYSTATSMALFORMEDTLV, COUNTER32, RONLY, + ldpEntityStatsTable, 5, {1, 2, 4, 1, 10}}, + { MPLSLDPENTITYSTATSKEEPALIVEEXP, COUNTER32, RONLY, + ldpEntityStatsTable, 5, {1, 2, 4, 1, 11}}, + { MPLSLDPENTITYSTATSSHUTDOWNRCVNOTIFY, COUNTER32, RONLY, + ldpEntityStatsTable, 5, {1, 2, 4, 1, 12}}, + { MPLSLDPENTITYSTATSSHUTDOWNSENTNOTIFY, COUNTER32, RONLY, + ldpEntityStatsTable, 5, {1, 2, 4, 1, 13}}, + /* MPLS LDP mplsLdpPeerTable */ {MPLSLDPPEERLDPID, STRING, RONLY, ldpPeerTable, 5, {1, 3, 2, 1, 1}}, {MPLSLDPPEERLABELDISTMETHOD, INTEGER, RONLY, ldpPeerTable, @@ -949,6 +1100,12 @@ static struct variable ldpe_variables[] = { {MPLSLDPSESSIONDISCONTINUITYTIME, TIMESTAMP, RONLY, ldpSessionTable, 5, {1, 3, 3, 1, 8}}, + /* MPLS LDP mplsLdpSessionStatsTable */ + {MPLSLDPSESSIONSTATSUNKNOWNMESTYPEERRORS, COUNTER32, RONLY, + ldpSessionStatsTable, 5, {1, 3, 4, 1, 1}}, + {MPLSLDPSESSIONSTATSUNKNOWNTLVERRORS, COUNTER32, RONLY, + ldpSessionStatsTable, 5, {1, 3, 4, 1, 2}}, + /* MPLS LDP mplsLdpHelloAdjacencyTable. */ {MPLSLDPHELLOADJACENCYINDEX, UNSIGNED32, RONLY, ldpHelloAdjacencyTable, 6, {1, 3, 5, 1, 1, 1}}, diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h index 103f4f228..73c81349c 100644 --- a/ldpd/ldpd.h +++ b/ldpd/ldpd.h @@ -435,9 +435,27 @@ struct ldp_stats { uint32_t labelrel_rcvd; uint32_t labelabreq_sent; uint32_t labelabreq_rcvd; + uint32_t unknown_tlv; + uint32_t unknown_msg; }; +struct ldp_entity_stats { + uint32_t session_attempts; + uint32_t session_rejects_hello; + uint32_t session_rejects_ad; + uint32_t session_rejects_max_pdu; + uint32_t session_rejects_lr; + uint32_t bad_ldp_id; + uint32_t bad_pdu_len; + uint32_t bad_msg_len; + uint32_t bad_tlv_len; + uint32_t malformed_tlv; + uint32_t keepalive_timer_exp; + uint32_t shutdown_rcv_notify; + uint32_t shutdown_send_notify; +}; + struct l2vpn_if { RB_ENTRY(l2vpn_if) entry; struct l2vpn *l2vpn; @@ -565,6 +583,7 @@ struct ldpd_conf { uint16_t wait_for_sync_interval; int flags; time_t config_change_time; + struct ldp_entity_stats stats; QOBJ_FIELDS }; DECLARE_QOBJ_TYPE(ldpd_conf) diff --git a/ldpd/notification.c b/ldpd/notification.c index f84e0f893..3ecf5d4ba 100644 --- a/ldpd/notification.c +++ b/ldpd/notification.c @@ -69,6 +69,36 @@ send_notification_full(struct tcp_conn *tcp, struct notify_msg *nm) tcp->nbr->stats.notif_sent++; } + /* update SNMP session counters */ + switch (nm->status_code) { + case S_NO_HELLO: + leconf->stats.session_rejects_hello++; + break; + case S_BAD_LDP_ID: + leconf->stats.bad_ldp_id++; + break; + case S_BAD_PDU_LEN: + leconf->stats.bad_pdu_len++; + break; + case S_BAD_MSG_LEN: + leconf->stats.bad_msg_len++; + break; + case S_BAD_TLV_LEN: + leconf->stats.bad_tlv_len++; + break; + case S_BAD_TLV_VAL: + leconf->stats.malformed_tlv++; + break; + case S_KEEPALIVE_TMR: + leconf->stats.keepalive_timer_exp++; + break; + case S_SHUTDOWN: + leconf->stats.shutdown_send_notify++; + break; + default: + break; + } + evbuf_enqueue(&tcp->wbuf, buf); } @@ -122,6 +152,7 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len) if (len < STATUS_SIZE) { session_shutdown(nbr, S_BAD_MSG_LEN, msg.id, msg.type); + leconf->stats.bad_msg_len++; return (-1); } memcpy(&st, buf, sizeof(st)); @@ -129,6 +160,7 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len) if (ntohs(st.length) > STATUS_SIZE - TLV_HDR_SIZE || ntohs(st.length) > len - TLV_HDR_SIZE) { session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); + leconf->stats.bad_tlv_len++; return (-1); } buf += STATUS_SIZE; @@ -145,6 +177,7 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len) if (len < sizeof(tlv)) { session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); + leconf->stats.bad_tlv_len++; return (-1); } @@ -153,6 +186,7 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len) tlv_len = ntohs(tlv.length); if (tlv_len + TLV_HDR_SIZE > len) { session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type); + leconf->stats.bad_tlv_len++; return (-1); } buf += TLV_HDR_SIZE; @@ -182,14 +216,17 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len) if (tlen != tlv_len) { session_shutdown(nbr, S_BAD_TLV_VAL, msg.id, msg.type); + leconf->stats.bad_tlv_len++; return (-1); } nm.flags |= F_NOTIF_FEC; break; default: - if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) + if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) { + nbr->stats.unknown_tlv++; send_notification_rtlvs(nbr, S_UNKNOWN_TLV, msg.id, msg.type, tlv_type, tlv_len, buf); + } /* ignore unknown tlv */ break; } @@ -243,21 +280,57 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len) * initialization, it SHOULD transmit a Shutdown message and * then close the transport connection". */ - if (nbr->state != NBR_STA_OPER && nm.status_code == S_SHUTDOWN) + if (nbr->state != NBR_STA_OPER && + nm.status_code == S_SHUTDOWN) { + leconf->stats.session_attempts++; send_notification(nbr->tcp, S_SHUTDOWN, msg.id, msg.type); + } + leconf->stats.shutdown_rcv_notify++; nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION); return (-1); } - /* lde needs to know about a few notification messages */ + /* lde needs to know about a few notification messages + * and update SNMP session counters + */ switch (nm.status_code) { case S_PW_STATUS: case S_ENDOFLIB: ldpe_imsg_compose_lde(IMSG_NOTIFICATION, nbr->peerid, 0, &nm, sizeof(nm)); break; + case S_NO_HELLO: + leconf->stats.session_rejects_hello++; + break; + case S_PARM_ADV_MODE: + leconf->stats.session_rejects_ad++; + break; + case S_MAX_PDU_LEN: + leconf->stats.session_rejects_max_pdu++; + break; + case S_PARM_L_RANGE: + leconf->stats.session_rejects_lr++; + break; + case S_BAD_LDP_ID: + leconf->stats.bad_ldp_id++; + break; + case S_BAD_PDU_LEN: + leconf->stats.bad_pdu_len++; + break; + case S_BAD_MSG_LEN: + leconf->stats.bad_msg_len++; + break; + case S_BAD_TLV_LEN: + leconf->stats.bad_tlv_len++; + break; + case S_BAD_TLV_VAL: + leconf->stats.malformed_tlv++; + break; + case S_SHUTDOWN: + leconf->stats.shutdown_rcv_notify++; + break; default: break; } diff --git a/ldpd/packet.c b/ldpd/packet.c index fdcaa79d2..8735faf3d 100644 --- a/ldpd/packet.c +++ b/ldpd/packet.c @@ -560,9 +560,11 @@ session_read(struct thread *thread) default: log_debug("%s: unknown LDP message from nbr %pI4", __func__, &nbr->id); - if (!(ntohs(msg->type) & UNKNOWN_FLAG)) + if (!(ntohs(msg->type) & UNKNOWN_FLAG)) { + nbr->stats.unknown_msg++; send_notification(nbr->tcp, S_UNKNOWN_MSG, msg->id, msg->type); + } /* ignore the message */ ret = 0; break; @@ -667,6 +669,12 @@ session_shutdown(struct nbr *nbr, uint32_t status, uint32_t msg_id, case NBR_STA_INITIAL: case NBR_STA_OPENREC: case NBR_STA_OPENSENT: + /* update SNMP session counters during initialization */ + leconf->stats.session_attempts++; + send_notification(nbr->tcp, status, msg_id, msg_type); + + nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION); + break; case NBR_STA_OPER: send_notification(nbr->tcp, status, msg_id, msg_type); |