]> git.puffer.fish Git - mirror/frr.git/commitdiff
ldpd: Add support for the read-only snmp mib objects that are statistics
authorKaren Schoener <karen@voltanet.io>
Mon, 15 Mar 2021 17:44:12 +0000 (13:44 -0400)
committerKaren Schoener <karen@voltanet.io>
Tue, 16 Mar 2021 14:23:34 +0000 (10:23 -0400)
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>
ldpd/ldp_snmp.c
ldpd/ldpd.h
ldpd/notification.c
ldpd/packet.c

index c9b37c0d2786baa65ff72e7e1b45cf7589ba11e4..97dde616a78c524c2f5a1977514125b0e6836a96 100644 (file)
@@ -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}},
index 103f4f228dfa799888b7bf27d7f592b5252883b7..73c81349ce4babc409c96c79186f03fda06cd771 100644 (file)
@@ -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)
index f84e0f893b8787c3ea5c3de02402a399f4124e30..3ecf5d4ba5919af7fc7dc80292d0bb504950f332 100644 (file)
@@ -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;
        }
index fdcaa79d2396015c1d32b921aff4eefe35ba2792..8735faf3dd1aefd08367833d601d3bc54fdada8b 100644 (file)
@@ -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);