summaryrefslogtreecommitdiffstats
path: root/ldpd
diff options
context:
space:
mode:
authorKaren Schoener <karen@voltanet.io>2021-03-15 18:44:12 +0100
committerKaren Schoener <karen@voltanet.io>2021-03-16 15:23:34 +0100
commitd4d6e7d87e6630944cbd5a53620ad4658c8dbf7a (patch)
treeb400f0f6d05659a57b493b4314f3c634d3cdd70e /ldpd
parentMerge pull request #8260 from volta-networks/fix_isis_snmp_test (diff)
downloadfrr-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.c157
-rw-r--r--ldpd/ldpd.h19
-rw-r--r--ldpd/notification.c79
-rw-r--r--ldpd/packet.c10
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);