// SPDX-License-Identifier: GPL-2.0-or-later /* * LDP SNMP support * Copyright (C) 2020 Volta Networks, Inc. */ /* * This is minimal read-only implementations providing * mplsLdpModuleReadOnlyCompliance as described in RFC 3815. */ #include #include #include #include "vrf.h" #include "if.h" #include "log.h" #include "prefix.h" #include "table.h" #include "command.h" #include "memory.h" #include "smux.h" #include "libfrr.h" #include "lib/version.h" #include "ldpd.h" #include "ldpe.h" /* SNMP value hack. */ #define COUNTER32 ASN_COUNTER #define INTEGER ASN_INTEGER #define UNSIGNED32 ASN_GAUGE #define TIMESTAMP ASN_TIMETICKS #define TIMETICKS ASN_TIMETICKS #define STRING ASN_OCTET_STR #define IPADDRESS ASN_IPADDRESS #define LDP_LSRID_IDX_LEN 6 #define LDP_ENTITY_IDX_LEN 1 #define LDP_ADJACENCY_IDX_LEN 1 /* MPLS-LDP-STD-MIB. */ #define MPLS_LDP_STD_MIB 1, 3, 6, 1, 2, 1, 10, 166, 4 #define MPLS_LDP_LSR_ID 0 #define MPLS_LDP_LSR_LOOP_DETECTION_CAPABLE 0 #define MPLS_LDP_ENTITY_LAST_CHANGE 0 #define MPLS_LDP_ENTITY_INDEX_NEXT 0 /* Declare static local variables for convenience. */ SNMP_LOCAL_VARIABLES /* LDP-MIB instances. */ static oid ldp_oid[] = {MPLS_LDP_STD_MIB}; static oid ldp_trap_oid[] = {MPLS_LDP_STD_MIB, 0}; static uint8_t snmp_ldp_rtrid[6] = {0, 0, 0, 0, 0}; #define LDP_DEFAULT_ENTITY_INDEX 1 #define MPLSLDPLSRLOOPDETECTIONCAPABLE_NONE 1 #define MPLSLDPLSRLOOPDETECTIONCAPABLE_OTHER 2 #define MPLSLDPLSRLOOPDETECTIONCAPABLE_HOPCOUNT 3 #define MPLSLDPLSRLOOPDETECTIONCAPABLE_PATHVECTOR 4 #define MPLSLDPLSRLOOPDETECTIONCAPABLE_HOPCOUNTANDPATHVECTOR 5 /* MPLS LDP mplsLdpHelloAdjacencyTable. */ #define MPLSLDPHELLOADJACENCYINDEX 1 #define MPLSLDPHELLOADJACENCYHOLDTIMEREM 2 #define MPLSLDPHELLOADJACENCYHOLDTIME 3 #define MPLSLDPHELLOADJACENCYTYPE 4 /* enums for column mplsLdpHelloAdjacencyType */ #define MPLSLDPHELLOADJACENCYTYPE_LINK 1 #define MPLSLDPHELLOADJACENCYTYPE_TARGETED 2 #define MPLSLDPPEERTRANSPORTADDRTYPE_UNKNOWN 0 #define MPLSLDPPEERTRANSPORTADDRTYPE_IPV4 1 #define MPLSLDPPEERTRANSPORTADDRTYPE_IPV6 2 #define MPLSLDPPEERTRANSPORTADDRTYPE_IPV4Z 3 #define MPLSLDPPEERTRANSPORTADDRTYPE_IPV6Z 4 #define MPLSLDPPEERTRANSPORTADDRTYPE_DNS 16 #define DOWNSTREAMONDEMAND 1 #define DOWNSTREAMUNSOLICITED 2 #define CONSERVATIVERETENTION 1 #define LIBERALRETENTION 2 #define TRANSPORTADDRINTERFACE 1 #define TRANSPORTADDRLOOPBACK 2 #define LABELTYPEGENERIC 1 #define STORAGETYPENONVOLATILE 3 #define ROWSTATUSACTIVE 4 #define ADMINSTATUSENABLED 1 #define OPERSTATUSENABLED 2 /* MPLS LDP mplsLdpPeerTable */ #define MPLSLDPPEERLDPID 1 #define MPLSLDPPEERLABELDISTMETHOD 2 #define MPLSLDPPEERPATHVECTORLIMIT 3 #define MPLSLDPPEERTRANSPORTADDRTYPE 4 #define MPLSLDPPEERTRANSPORTADDR 5 #define MPLSLDPSESSIONROLE_UNKNOWN 1 #define MPLSLDPSESSIONROLE_ACTIVE 2 #define MPLSLDPSESSIONROLE_PASSIVE 3 #define MPLSLDPSESSIONSTATE_NONEXISTENT 1 #define MPLSLDPSESSIONSTATE_INITIALIZED 2 #define MPLSLDPSESSIONSTATE_OPENREC 3 #define MPLSLDPSESSIONSTATE_OPENSENT 4 #define MPLSLDPSESSIONSTATE_OPERATIONAL 5 /* MPLS LDP mplsLdpSessionTable */ #define MPLSLDPSESSIONSTATELASTCHANGE 1 #define MPLSLDPSESSIONSTATE 2 #define MPLSLDPSESSIONROLE 3 #define MPLSLDPSESSIONPROTOCOLVERSION 4 #define MPLSLDPSESSIONKEEPALIVEHOLDTIMEREM 5 #define MPLSLDPSESSIONKEEPALIVETIME 6 #define MPLSLDPSESSIONMAXPDULENGTH 7 #define MPLSLDPSESSIONDISCONTINUITYTIME 8 /* MPLS LDP mplsLdpEntityTable */ #define MPLSLDPENTITYLDPID 1 #define MPLSLDPENTITYINDEX 2 #define MPLSLDPENTITYPROTOCOLVERSION 3 #define MPLSLDPENTITYADMINSTATUS 4 #define MPLSLDPENTITYOPERSTATUS 5 #define MPLSLDPENTITYTCPPORT 6 #define MPLSLDPENTITYUDPDSCPORT 7 #define MPLSLDPENTITYMAXPDULENGTH 8 #define MPLSLDPENTITYKEEPALIVEHOLDTIMER 9 #define MPLSLDPENTITYHELLOHOLDTIMER 10 #define MPLSLDPENTITYINITSESSIONTHRESHOLD 11 #define MPLSLDPENTITYLABELDISTMETHOD 12 #define MPLSLDPENTITYLABELRETENTIONMODE 13 #define MPLSLDPENTITYPATHVECTORLIMIT 14 #define MPLSLDPENTITYHOPCOUNTLIMIT 15 #define MPLSLDPENTITYTRANSPORTADDRKIND 16 #define MPLSLDPENTITYTARGETPEER 17 #define MPLSLDPENTITYTARGETPEERADDRTYPE 18 #define MPLSLDPENTITYTARGETPEERADDR 19 #define MPLSLDPENTITYLABELTYPE 20 #define MPLSLDPENTITYDISCONTINUITYTIME 21 #define MPLSLDPENTITYSTORAGETYPE 22 #define MPLSLDPENTITYROWSTATUS 23 /* MPLS LDP mplsLdpEntityStatsTable */ #define MPLSLDPENTITYSTATSSESSIONATTEMPTS 1 #define MPLSLDPENTITYSTATSSESSIONREJHELLO 2 #define MPLSLDPENTITYSTATSSESSIONREJAD 3 #define MPLSLDPENTITYSTATSSESSIONREJMAXPDU 4 #define MPLSLDPENTITYSTATSSESSIONREJLR 5 #define MPLSLDPENTITYSTATSBADLDPID 6 #define MPLSLDPENTITYSTATSBADPDULENGTH 7 #define MPLSLDPENTITYSTATSBADMSGLENGTH 8 #define MPLSLDPENTITYSTATSBADTLVLENGTH 9 #define MPLSLDPENTITYSTATSMALFORMEDTLV 10 #define MPLSLDPENTITYSTATSKEEPALIVEEXP 11 #define MPLSLDPENTITYSTATSSHUTDOWNRCVNOTIFY 12 #define MPLSLDPENTITYSTATSSHUTDOWNSENTNOTIFY 13 #define MPLSLDPSESSIONSTATSUNKNOWNMESTYPEERRORS 1 #define MPLSLDPSESSIONSTATSUNKNOWNTLVERRORS 2 static uint8_t *ldpLsrId(struct variable *v, oid name[], size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { if (smux_header_generic(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; *var_len = 4; return (uint8_t *)&leconf->rtr_id.s_addr; } static uint8_t *ldpLoopDetectCap(struct variable *v, oid name[], size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { if (smux_header_generic(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; return SNMP_INTEGER(MPLSLDPLSRLOOPDETECTIONCAPABLE_NONE); } extern uint32_t ldp_start_time; static uint8_t *ldpEntityLastChange(struct variable *v, oid name[], size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { if (smux_header_generic(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; *var_len = sizeof(time_t); return (uint8_t *) &(leconf->config_change_time); } static uint8_t *ldpEntityIndexNext(struct variable *v, oid name[], size_t *length,int exact, size_t *var_len, WriteMethod **write_method) { if (smux_header_generic(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; return SNMP_INTEGER(0); } #define LDP_ENTITY_TOTAL_LEN 21 #define LDP_ENTITY_MAX_IDX_LEN 6 static struct ldpd_af_conf *ldpEntityTable_lookup(struct variable *v, oid *name, size_t *length, int exact, uint32_t *index) { int len; struct ldpd_af_conf *af_v4, *af_v6; af_v4 = &leconf->ipv4; af_v6 = &leconf->ipv6; if (exact) { if (*length != LDP_ENTITY_TOTAL_LEN) return NULL; if (leconf->trans_pref == DUAL_STACK_LDPOV6 && af_v6->flags & F_LDPD_AF_ENABLED) { *index = 2; return af_v6; } else { *index = 1; return af_v4; } } else { /* only support one router id so can just skip */ len = *length - v->namelen - LDP_ENTITY_MAX_IDX_LEN; if (len <= 0) { if (leconf->trans_pref == DUAL_STACK_LDPOV6 && af_v6->flags & F_LDPD_AF_ENABLED) { *index = 2; return af_v6; } else { *index = 1; return af_v4; } } } return NULL; } static uint8_t *ldpEntityTable(struct variable *v, oid name[], size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { struct ldpd_af_conf *af; struct in_addr entityLdpId = {.s_addr = 0}; uint32_t index = 0; *write_method = NULL; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; af = ldpEntityTable_lookup(v, name, length, exact, &index); if (af == NULL) return NULL; if (!exact) { 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_in_addr(name + v->namelen, &entityLdpId); 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 MPLSLDPENTITYLDPID: *var_len = 6; memcpy (snmp_ldp_rtrid, &entityLdpId, IN_ADDR_SIZE); return (uint8_t *)snmp_ldp_rtrid; case MPLSLDPENTITYINDEX: return SNMP_INTEGER(LDP_DEFAULT_ENTITY_INDEX); case MPLSLDPENTITYPROTOCOLVERSION: return SNMP_INTEGER(LDP_VERSION); case MPLSLDPENTITYADMINSTATUS: return SNMP_INTEGER(ADMINSTATUSENABLED); case MPLSLDPENTITYOPERSTATUS: return SNMP_INTEGER(OPERSTATUSENABLED); case MPLSLDPENTITYTCPPORT: return SNMP_INTEGER(LDP_PORT); case MPLSLDPENTITYUDPDSCPORT: return SNMP_INTEGER(LDP_PORT); case MPLSLDPENTITYMAXPDULENGTH: return SNMP_INTEGER(LDP_MAX_LEN); case MPLSLDPENTITYKEEPALIVEHOLDTIMER: return SNMP_INTEGER(af->keepalive); case MPLSLDPENTITYHELLOHOLDTIMER: return SNMP_INTEGER(af->lhello_holdtime); case MPLSLDPENTITYINITSESSIONTHRESHOLD: return SNMP_INTEGER(0); /* not supported */ case MPLSLDPENTITYLABELDISTMETHOD: return SNMP_INTEGER(DOWNSTREAMUNSOLICITED); case MPLSLDPENTITYLABELRETENTIONMODE: return SNMP_INTEGER(LIBERALRETENTION); case MPLSLDPENTITYPATHVECTORLIMIT: return SNMP_INTEGER(0); /* not supported */ case MPLSLDPENTITYHOPCOUNTLIMIT: return SNMP_INTEGER(0); case MPLSLDPENTITYTRANSPORTADDRKIND: return SNMP_INTEGER(TRANSPORTADDRLOOPBACK); case MPLSLDPENTITYTARGETPEER: return SNMP_INTEGER(1); case MPLSLDPENTITYTARGETPEERADDRTYPE: if (index == 1) return SNMP_INTEGER(MPLSLDPPEERTRANSPORTADDRTYPE_IPV4); else return SNMP_INTEGER(MPLSLDPPEERTRANSPORTADDRTYPE_IPV6); case MPLSLDPENTITYTARGETPEERADDR: if (index == 1) { *var_len = sizeof(af->trans_addr.v4); return ((uint8_t *)&af->trans_addr.v4); }else { *var_len = sizeof(af->trans_addr.v6); return ((uint8_t *)&af->trans_addr.v6); } case MPLSLDPENTITYLABELTYPE: return SNMP_INTEGER(LABELTYPEGENERIC); case MPLSLDPENTITYDISCONTINUITYTIME: return SNMP_INTEGER(0); case MPLSLDPENTITYSTORAGETYPE: return SNMP_INTEGER(STORAGETYPENONVOLATILE); case MPLSLDPENTITYROWSTATUS: return SNMP_INTEGER(ROWSTATUSACTIVE); default: return NULL; } 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_in_addr(name + v->namelen, &entityLdpId); 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( struct variable *v, oid name[], size_t *length, struct in_addr *entityLdpId, uint32_t *entityIndex, struct in_addr *peerLdpId, uint32_t *adjacencyIndex) { oid *offset = name + v->namelen; int offsetlen = *length - v->namelen; int len = offsetlen; if (len > LDP_ADJACENCY_ENTRY_MAX_IDX_LEN) len = LDP_ADJACENCY_ENTRY_MAX_IDX_LEN; if (len >= LDP_LSRID_IDX_LEN) oid2in_addr(offset, sizeof(struct in_addr), entityLdpId); offset += LDP_LSRID_IDX_LEN; offsetlen -= LDP_LSRID_IDX_LEN; len = offsetlen; if (len > LDP_ENTITY_IDX_LEN) len = LDP_ENTITY_IDX_LEN; if (len >= LDP_ENTITY_IDX_LEN) *entityIndex = offset[0]; offset += LDP_ENTITY_IDX_LEN; offsetlen -= LDP_ENTITY_IDX_LEN; len = offsetlen; if (len > LDP_LSRID_IDX_LEN) len = LDP_LSRID_IDX_LEN; if (len >= LDP_LSRID_IDX_LEN) oid2in_addr(offset, sizeof(struct in_addr), peerLdpId); offset += LDP_LSRID_IDX_LEN; offsetlen -= LDP_LSRID_IDX_LEN; len = offsetlen; if (len > LDP_ADJACENCY_IDX_LEN) len = LDP_ADJACENCY_IDX_LEN; if (len >= LDP_ADJACENCY_IDX_LEN) *adjacencyIndex = offset[0]; } static struct adj * nbr_get_adj_by_index(struct nbr *nbr, uint32_t adjacencyIndex) { struct adj *adj; uint32_t i = 0; RB_FOREACH(adj, nbr_adj_head, &nbr->adj_tree) if (++i == adjacencyIndex) return adj; return NULL; } static struct ctl_adj * ldpHelloAdjacencyTable_lookup_helper( struct in_addr *entityLdpId, uint32_t *entityIndex, struct in_addr *peerLdpId, uint32_t *adjacencyIndex) { struct ctl_adj *ctl_adj = NULL; struct adj *adj = NULL; struct nbr *cur_nbr = nbr_find_ldpid(peerLdpId->s_addr); if (cur_nbr) /* If found nbr, then look to see if the * adjacency exists */ adj = nbr_get_adj_by_index(cur_nbr, *adjacencyIndex); if (adj) ctl_adj = adj_to_ctl(adj); return ctl_adj; } static struct ctl_adj * ldpHelloAdjacencyTable_next_helper( int first, struct in_addr *entityLdpId, uint32_t *entityIndex, struct in_addr *peerLdpId, uint32_t *adjacencyIndex) { struct ctl_adj *ctl_adj = NULL; struct nbr *nbr = NULL; struct adj *adj = NULL; if (first) nbr = nbr_get_first_ldpid(); else { struct nbr *cur_nbr = nbr_find_ldpid(peerLdpId->s_addr); if (cur_nbr) /* If found nbr, then look to see if the * adjacency exists */ adj = nbr_get_adj_by_index(cur_nbr, *adjacencyIndex + 1); if (adj) *adjacencyIndex += 1; else nbr = nbr_get_next_ldpid(peerLdpId->s_addr); } if (!adj && nbr) { adj = RB_MIN(nbr_adj_head, &nbr->adj_tree); *adjacencyIndex = 1; } if (adj) ctl_adj = adj_to_ctl(adj); return ctl_adj; } #define HELLO_ADJ_MAX_IDX_LEN 14 static struct ctl_adj * ldpHelloAdjacencyTable_lookup(struct variable *v, oid name[], size_t *length, int exact, struct in_addr *entityLdpId, uint32_t *entityIndex, struct in_addr *peerLdpId, uint32_t *adjacencyIndex) { struct ctl_adj *hello_adj = NULL; if (exact) { if (*length < HELLO_ADJ_MAX_IDX_LEN) return NULL; ldpHelloAdjacencyTable_oid_to_index( v, name, length, entityLdpId, entityIndex, peerLdpId, adjacencyIndex); hello_adj = ldpHelloAdjacencyTable_lookup_helper( entityLdpId, entityIndex, peerLdpId, adjacencyIndex); } else { int first = 0; int offsetlen = *length - v->namelen; if (offsetlen < HELLO_ADJ_MAX_IDX_LEN) first = 1; ldpHelloAdjacencyTable_oid_to_index( v, name, length, entityLdpId, entityIndex, peerLdpId, adjacencyIndex); hello_adj = ldpHelloAdjacencyTable_next_helper(first, entityLdpId, entityIndex, peerLdpId, adjacencyIndex); } return hello_adj; } static uint8_t *ldpHelloAdjacencyTable(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}; uint32_t adjacencyIndex = 0; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; struct ctl_adj *ctl_adj = ldpHelloAdjacencyTable_lookup(v, name, length, exact, &entityLdpId, &entityIndex, &peerLdpId, &adjacencyIndex); if (!ctl_adj) return NULL; if (!exact) { /* Copy the name out */ memcpy(name, v->name, v->namelen * sizeof(oid)); /* Append index */ struct in_addr entityLdpId = {.s_addr = 0}; entityLdpId.s_addr = ldp_rtr_id_get(leconf); struct in_addr peerLdpId = ctl_adj->id; oid_copy_in_addr(name + v->namelen, &entityLdpId); name[v->namelen + 4] = 0; name[v->namelen + 5] = 0; name[v->namelen + 6] = LDP_DEFAULT_ENTITY_INDEX; oid_copy_in_addr(name + v->namelen + 7, &peerLdpId); name[v->namelen + 11] = 0; name[v->namelen + 12] = 0; name[v->namelen + 13] = adjacencyIndex; /* Set length */ *length = v->namelen + HELLO_ADJ_MAX_IDX_LEN; } switch (v->magic) { case MPLSLDPHELLOADJACENCYINDEX: return SNMP_INTEGER(adjacencyIndex); case MPLSLDPHELLOADJACENCYHOLDTIMEREM: return SNMP_INTEGER(ctl_adj->holdtime_remaining); case MPLSLDPHELLOADJACENCYHOLDTIME: return SNMP_INTEGER(ctl_adj->holdtime); case MPLSLDPHELLOADJACENCYTYPE: if (ctl_adj->type == HELLO_LINK) return SNMP_INTEGER(MPLSLDPHELLOADJACENCYTYPE_LINK); return SNMP_INTEGER(MPLSLDPHELLOADJACENCYTYPE_TARGETED); default: return NULL; } return NULL; } #define LDP_LSRID_IDX_LEN 6 #define LDP_ENTITY_IDX_LEN 1 #define LDP_PEER_ENTRY_MAX_IDX_LEN 13 static void ldpPeerTable_oid_to_index( struct variable *v, oid name[], size_t *length, struct in_addr *entityLdpId, uint32_t *entityIndex, struct in_addr *peerLdpId) { oid *offset = name + v->namelen; int offsetlen = *length - v->namelen; int len = offsetlen; if (len > LDP_PEER_ENTRY_MAX_IDX_LEN) len = LDP_PEER_ENTRY_MAX_IDX_LEN; if (len >= LDP_LSRID_IDX_LEN) oid2in_addr(offset, sizeof(struct in_addr), entityLdpId); offset += LDP_LSRID_IDX_LEN; offsetlen -= LDP_LSRID_IDX_LEN; len = offsetlen; if (len > LDP_ENTITY_IDX_LEN) len = LDP_ENTITY_IDX_LEN; if (len >= LDP_ENTITY_IDX_LEN) *entityIndex = offset[0]; offset += LDP_ENTITY_IDX_LEN; offsetlen -= LDP_ENTITY_IDX_LEN; len = offsetlen; if (len > LDP_LSRID_IDX_LEN) len = LDP_LSRID_IDX_LEN; if (len >= LDP_LSRID_IDX_LEN) oid2in_addr(offset, sizeof(struct in_addr), peerLdpId); } static struct ctl_nbr * ldpPeerTable_lookup_next(int first, struct in_addr peerLdpId) { struct nbr *nbr = NULL; struct ctl_nbr *ctl_nbr = NULL;; if (first) nbr = nbr_get_first_ldpid(); else nbr = nbr_get_next_ldpid(peerLdpId.s_addr); if (nbr) ctl_nbr = nbr_to_ctl(nbr); return ctl_nbr; } static struct ctl_nbr * ldpPeerTable_lookup(struct variable *v, oid name[], size_t *length, int exact, struct in_addr *entityLdpId, uint32_t *entityIndex, struct in_addr *peerLdpId) { struct ctl_nbr *ctl_nbr = NULL; struct nbr *nbr = NULL; int first = 0; if (exact) { if (*length < (long unsigned int)v->namelen + LDP_PEER_ENTRY_MAX_IDX_LEN) return NULL; ldpPeerTable_oid_to_index( v, name, length, entityLdpId, entityIndex, peerLdpId); nbr = nbr_find_ldpid(peerLdpId->s_addr); if (nbr) ctl_nbr = nbr_to_ctl(nbr); return ctl_nbr; } else { int offsetlen = *length - v->namelen; if (offsetlen < LDP_LSRID_IDX_LEN) first = 1; ldpPeerTable_oid_to_index( v, name, length, entityLdpId, entityIndex, peerLdpId); ctl_nbr = ldpPeerTable_lookup_next(first, *peerLdpId); return ctl_nbr; } return NULL; } static uint8_t *ldpPeerTable(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}; struct ctl_nbr *ctl_nbr; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; 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_in_addr(name + v->namelen, &entityLdpId); name[v->namelen + 4] = 0; name[v->namelen + 5] = 0; name[v->namelen + 6] = entityIndex; oid_copy_in_addr(name + v->namelen + 7, &peerLdpId); name[v->namelen + 11] = 0; name[v->namelen + 12] = 0; /* Set length */ *length = v->namelen + LDP_PEER_ENTRY_MAX_IDX_LEN; } switch (v->magic) { case MPLSLDPPEERLDPID: *var_len = 6; memcpy(snmp_ldp_rtrid, &ctl_nbr->id, IN_ADDR_SIZE); return snmp_ldp_rtrid; case MPLSLDPPEERLABELDISTMETHOD: return SNMP_INTEGER(DOWNSTREAMUNSOLICITED); case MPLSLDPPEERPATHVECTORLIMIT: return SNMP_INTEGER(0); case MPLSLDPPEERTRANSPORTADDRTYPE: if (ctl_nbr->af == AF_INET) return SNMP_INTEGER(MPLSLDPPEERTRANSPORTADDRTYPE_IPV4); else return SNMP_INTEGER(MPLSLDPPEERTRANSPORTADDRTYPE_IPV6); case MPLSLDPPEERTRANSPORTADDR: if (ctl_nbr->af == AF_INET) { *var_len = sizeof(ctl_nbr->raddr.v4); return ((uint8_t *)&ctl_nbr->raddr.v4); } else { *var_len = sizeof(ctl_nbr->raddr.v6); return ((uint8_t *)&ctl_nbr->raddr.v6); } default: return NULL; } return NULL; } static uint8_t *ldpSessionTable(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}; struct ctl_nbr *ctl_nbr; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; 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_in_addr(name + v->namelen, &entityLdpId); name[v->namelen + 4] = 0; name[v->namelen + 5] = 0; name[v->namelen + 6] = entityIndex; oid_copy_in_addr(name + v->namelen + 7, &peerLdpId); name[v->namelen + 11] = 0; name[v->namelen + 12] = 0; /* Set length */ *length = v->namelen + LDP_PEER_ENTRY_MAX_IDX_LEN; } switch (v->magic) { case MPLSLDPSESSIONSTATELASTCHANGE: *var_len = sizeof(time_t); return (uint8_t *) &(ctl_nbr->uptime); case MPLSLDPSESSIONSTATE: switch (ctl_nbr->nbr_state) { case NBR_STA_INITIAL: return SNMP_INTEGER(MPLSLDPSESSIONSTATE_INITIALIZED); case NBR_STA_OPENREC: return SNMP_INTEGER(MPLSLDPSESSIONSTATE_OPENREC); case NBR_STA_OPENSENT: return SNMP_INTEGER(MPLSLDPSESSIONSTATE_OPENSENT); case NBR_STA_OPER: return SNMP_INTEGER(MPLSLDPSESSIONSTATE_OPERATIONAL); default: return SNMP_INTEGER(MPLSLDPSESSIONSTATE_NONEXISTENT); } case MPLSLDPSESSIONROLE: if (ldp_addrcmp(ctl_nbr->af, &ctl_nbr->laddr, &ctl_nbr->raddr) > 0) return SNMP_INTEGER(MPLSLDPSESSIONROLE_ACTIVE); else return SNMP_INTEGER(MPLSLDPSESSIONROLE_PASSIVE); case MPLSLDPSESSIONPROTOCOLVERSION: return SNMP_INTEGER(LDP_VERSION); case MPLSLDPSESSIONKEEPALIVEHOLDTIMEREM: return SNMP_INTEGER(ctl_nbr->hold_time_remaining); case MPLSLDPSESSIONKEEPALIVETIME: return SNMP_INTEGER(ctl_nbr->holdtime); case MPLSLDPSESSIONMAXPDULENGTH: if (ctl_nbr->nbr_state == NBR_STA_OPER) return SNMP_INTEGER(ctl_nbr->max_pdu_len); else return SNMP_INTEGER(LDP_MAX_LEN); case MPLSLDPSESSIONDISCONTINUITYTIME: return SNMP_INTEGER(0); /* not supported */ default: return NULL; } 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_in_addr(name + v->namelen, &entityLdpId); name[v->namelen + 4] = 0; name[v->namelen + 5] = 0; name[v->namelen + 6] = entityIndex; oid_copy_in_addr(name + v->namelen + 7, &peerLdpId); 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, ldpLoopDetectCap, 3, {1, 1, 2}}, {MPLS_LDP_ENTITY_LAST_CHANGE, TIMESTAMP, RONLY, ldpEntityLastChange, 3, {1, 2, 1}}, {MPLS_LDP_ENTITY_INDEX_NEXT, UNSIGNED32, RONLY, ldpEntityIndexNext, 3, {1, 2, 2}}, /* MPLS LDP mplsLdpEntityTable. */ {MPLSLDPENTITYLDPID, STRING, RONLY, ldpEntityTable, 5, {1, 2, 3, 1, 1}}, {MPLSLDPENTITYINDEX, UNSIGNED32, RONLY, ldpEntityTable, 5, {1, 2, 3, 1, 2}}, {MPLSLDPENTITYPROTOCOLVERSION, UNSIGNED32, RONLY, ldpEntityTable, 5, {1, 2, 3, 1, 3}}, {MPLSLDPENTITYADMINSTATUS, INTEGER, RONLY, ldpEntityTable, 5, {1, 2, 3, 1, 4}}, {MPLSLDPENTITYOPERSTATUS, INTEGER, RONLY, ldpEntityTable, 5, {1, 2, 3, 1, 5}}, {MPLSLDPENTITYTCPPORT, UNSIGNED32, RONLY, ldpEntityTable, 5, {1, 2, 3, 1, 6}}, {MPLSLDPENTITYUDPDSCPORT, UNSIGNED32, RONLY, ldpEntityTable, 5, {1, 2, 3, 1, 7}}, {MPLSLDPENTITYMAXPDULENGTH, UNSIGNED32, RONLY, ldpEntityTable, 5, {1, 2, 3, 1, 8}}, {MPLSLDPENTITYKEEPALIVEHOLDTIMER, UNSIGNED32, RONLY, ldpEntityTable, 5, {1, 2, 3, 1, 9}}, {MPLSLDPENTITYHELLOHOLDTIMER, UNSIGNED32, RONLY, ldpEntityTable, 5, {1, 2, 3, 1, 10}}, {MPLSLDPENTITYINITSESSIONTHRESHOLD, INTEGER, RONLY, ldpEntityTable, 5, {1, 2, 3, 1, 11}}, {MPLSLDPENTITYLABELDISTMETHOD, INTEGER, RONLY, ldpEntityTable, 5, {1, 2, 3, 1, 12}}, {MPLSLDPENTITYLABELRETENTIONMODE, INTEGER, RONLY, ldpEntityTable, 5, {1, 2, 3, 1, 13}}, {MPLSLDPENTITYPATHVECTORLIMIT, INTEGER, RONLY, ldpEntityTable, 5, {1, 2, 3, 1, 14}}, {MPLSLDPENTITYHOPCOUNTLIMIT, INTEGER, RONLY, ldpEntityTable, 5, {1, 2, 3, 1, 15}}, {MPLSLDPENTITYTRANSPORTADDRKIND, INTEGER, RONLY, ldpEntityTable, 5, {1, 2, 3, 1, 16}}, {MPLSLDPENTITYTARGETPEER, INTEGER, RONLY, ldpEntityTable, 5, {1, 2, 3, 1, 17}}, {MPLSLDPENTITYTARGETPEERADDRTYPE, INTEGER, RONLY, ldpEntityTable, 5, {1, 2, 3, 1, 18}}, {MPLSLDPENTITYTARGETPEERADDR, STRING, RONLY, ldpEntityTable, 5, {1, 2, 3, 1, 19}}, {MPLSLDPENTITYLABELTYPE, INTEGER, RONLY, ldpEntityTable, 5, {1, 2, 3, 1, 20}}, {MPLSLDPENTITYDISCONTINUITYTIME, TIMESTAMP, RONLY, ldpEntityTable, 5, {1, 2, 3, 1, 21}}, {MPLSLDPENTITYSTORAGETYPE, INTEGER, RONLY, ldpEntityTable, 5, {1, 2, 3, 1, 22}}, {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, 5, {1, 3, 2, 1, 2}}, {MPLSLDPPEERPATHVECTORLIMIT, INTEGER, RONLY, ldpPeerTable, 5, {1, 3, 2, 1, 3}}, {MPLSLDPPEERTRANSPORTADDRTYPE, INTEGER, RONLY, ldpPeerTable, 5, {1, 3, 2, 1, 4}}, {MPLSLDPPEERTRANSPORTADDR, STRING, RONLY, ldpPeerTable, 5, {1, 3, 2, 1, 5}}, /* MPLS LDP mplsLdpSessionTable */ {MPLSLDPSESSIONSTATELASTCHANGE, TIMESTAMP, RONLY, ldpSessionTable, 5, {1, 3, 3, 1, 1}}, {MPLSLDPSESSIONSTATE, INTEGER, RONLY, ldpSessionTable, 5, {1, 3, 3, 1, 2}}, {MPLSLDPSESSIONROLE, INTEGER, RONLY, ldpSessionTable, 5, {1, 3, 3, 1, 3}}, {MPLSLDPSESSIONPROTOCOLVERSION, UNSIGNED32, RONLY, ldpSessionTable, 5, {1, 3, 3, 1, 4}}, {MPLSLDPSESSIONKEEPALIVEHOLDTIMEREM, INTEGER, RONLY, ldpSessionTable, 5, {1, 3, 3, 1, 5}}, {MPLSLDPSESSIONKEEPALIVETIME, UNSIGNED32, RONLY, ldpSessionTable, 5, {1, 3, 3, 1, 6}}, {MPLSLDPSESSIONMAXPDULENGTH, UNSIGNED32, RONLY, ldpSessionTable, 5, {1, 3, 3, 1, 7}}, {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}}, {MPLSLDPHELLOADJACENCYHOLDTIMEREM, INTEGER, RONLY, ldpHelloAdjacencyTable, 6, {1, 3, 5, 1, 1, 2}}, {MPLSLDPHELLOADJACENCYHOLDTIME, UNSIGNED32, RONLY, ldpHelloAdjacencyTable, 6, {1, 3, 5, 1, 1, 3}}, {MPLSLDPHELLOADJACENCYTYPE, INTEGER, RONLY, ldpHelloAdjacencyTable, 6, {1, 3, 5, 1, 1, 4}}, }; static struct variable lde_variables[] = { }; static struct trap_object ldpSessionTrapList[] = { {5, {1, 3, 3, 1, MPLSLDPSESSIONSTATE}}, {5, {1, 3, 3, 1, MPLSLDPSESSIONDISCONTINUITYTIME}}, {5, {1, 3, 4, 1, MPLSLDPSESSIONSTATSUNKNOWNMESTYPEERRORS}}, {5, {1, 3, 4, 1, MPLSLDPSESSIONSTATSUNKNOWNTLVERRORS}}}; /* LDP TRAP. */ #define LDPINITSESSIONTHRESHOLDEXCEEDED 1 #define LDPPATHVECTORLIMITMISMATCH 2 #define LDPSESSIONUP 3 #define LDPSESSIONDOWN 4 static void ldpTrapSession(struct nbr * nbr, unsigned int sptrap) { oid index[sizeof(oid) * (LDP_PEER_ENTRY_MAX_IDX_LEN + 1)]; struct in_addr entityLdpId = {.s_addr = 0}; uint32_t entityIndex = 0; struct in_addr peerLdpId = {.s_addr = 0}; struct ctl_nbr *ctl_nbr = nbr_to_ctl(nbr); entityLdpId.s_addr = ldp_rtr_id_get(leconf); entityIndex = LDP_DEFAULT_ENTITY_INDEX; peerLdpId = ctl_nbr->id; oid_copy_in_addr(index, &entityLdpId); index[4] = 0; index[5] = 0; index[6] = entityIndex; oid_copy_in_addr(&index[7], &peerLdpId); index[11] = 0; index[12] = 0; index[LDP_PEER_ENTRY_MAX_IDX_LEN] = 0; smux_trap(ldpe_variables, array_size(ldpe_variables), ldp_trap_oid, array_size(ldp_trap_oid), ldp_oid, sizeof(ldp_oid) / sizeof(oid), index, LDP_PEER_ENTRY_MAX_IDX_LEN + 1, ldpSessionTrapList, array_size(ldpSessionTrapList), sptrap); } static void ldpTrapSessionUp(struct nbr * nbr) { ldpTrapSession(nbr, LDPSESSIONUP); } static void ldpTrapSessionDown(struct nbr * nbr) { ldpTrapSession(nbr, LDPSESSIONDOWN); } static int ldp_snmp_agentx_enabled(void) { main_imsg_compose_both(IMSG_AGENTX_ENABLED, NULL, 0); return 0; } static int ldp_snmp_nbr_state_change(struct nbr * nbr, int old_state) { if (old_state == nbr->state) return 0; if (nbr->state == NBR_STA_OPER) ldpTrapSessionUp(nbr); else if (old_state == NBR_STA_OPER) ldpTrapSessionDown(nbr); return 0; } static int ldp_snmp_init(struct thread_master *tm) { hook_register(agentx_enabled, ldp_snmp_agentx_enabled); smux_init(tm); return 0; } static int ldp_snmp_register_mib(struct thread_master *tm) { static int registered = 0; if (registered) return 0; registered = 1; smux_init(tm); smux_agentx_enable(); if (ldpd_process == PROC_LDE_ENGINE) REGISTER_MIB("mibII/ldp", lde_variables, variable, ldp_oid); else if (ldpd_process == PROC_LDP_ENGINE) { REGISTER_MIB("mibII/ldp", ldpe_variables, variable, ldp_oid); hook_register(ldp_nbr_state_change, ldp_snmp_nbr_state_change); } return 0; } static int ldp_snmp_module_init(void) { if (ldpd_process == PROC_MAIN) hook_register(frr_late_init, ldp_snmp_init); else hook_register(ldp_register_mib, ldp_snmp_register_mib); return 0; } FRR_MODULE_SETUP( .name = "ldp_snmp", .version = FRR_VERSION, .description = "ldp AgentX SNMP module", .init = ldp_snmp_module_init, );