diff --git a/ldpd/lde.c b/ldpd/lde.c index 69338b8bad..8fa74d1c3d 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -127,15 +127,13 @@ static struct quagga_signal_t lde_signals[] = void lde(void) { - struct thread thread; - #ifdef HAVE_SETPROCTITLE setproctitle("label decision engine"); #endif ldpd_process = PROC_LDE_ENGINE; log_procname = log_procnames[PROC_LDE_ENGINE]; - master = thread_master_create(NULL); + master = frr_init(); /* setup signal handler */ signal_init(master, array_size(lde_signals), lde_signals); @@ -157,9 +155,12 @@ lde(void) /* create base configuration */ ldeconf = config_new_empty(); - /* Fetch next active thread. */ + struct thread thread; while (thread_fetch(master, &thread)) thread_call(&thread); + + /* NOTREACHED */ + return; } void @@ -566,6 +567,9 @@ lde_dispatch_parent(struct thread *thread) memcpy(&init, imsg.data, sizeof(init)); lde_init(&init); break; + case IMSG_AGENTX_ENABLED: + ldp_agentx_enabled(); + break; case IMSG_RECONF_CONF: if ((nconf = malloc(sizeof(struct ldpd_conf))) == NULL) diff --git a/ldpd/ldp_snmp.c b/ldpd/ldp_snmp.c new file mode 100644 index 0000000000..c9b37c0d27 --- /dev/null +++ b/ldpd/ldp_snmp.c @@ -0,0 +1,1087 @@ +/* + * LDP SNMP support + * Copyright (C) 2020 Volta Networks, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * 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 "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_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 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; +} + +#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_addr(name + v->namelen, &entityLdpId, + sizeof(struct in_addr)); + name[v->namelen + 4] = 0; + name[v->namelen + 5] = 0; + name[v->namelen + 6] = LDP_DEFAULT_ENTITY_INDEX; + oid_copy_addr(name + v->namelen + 7, &peerLdpId, + sizeof(struct in_addr)); + 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_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; + + /* 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_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; + + /* 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 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 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 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_addr(index, &entityLdpId, sizeof(struct in_addr)); + index[4] = 0; + index[5] = 0; + index[6] = entityIndex; + oid_copy_addr(&index[7], &peerLdpId, sizeof(struct in_addr)); + 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() +{ + 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, ) diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c index 83e93ebbbc..14235a0f1f 100644 --- a/ldpd/ldpd.c +++ b/ldpd/ldpd.c @@ -86,6 +86,30 @@ static struct imsgev *iev_lde, *iev_lde_sync; static pid_t ldpe_pid; static pid_t lde_pid; +static struct frr_daemon_info ldpd_di; + +DEFINE_HOOK(ldp_register_mib, (struct thread_master * tm), (tm)) + +static void ldp_load_module(const char *name) +{ + const char *dir; + dir = ldpd_di.module_path ? ldpd_di.module_path : frr_moduledir; + char moderr[256]; + struct frrmod_runtime *module; + + module = frrmod_load(name, dir, moderr, sizeof(moderr)); + if (!module) { + fprintf(stderr, "%s: failed to load %s", __func__, name); + log_warnx("%s: failed to load %s", __func__, name); + } +} + +void ldp_agentx_enabled(void) +{ + ldp_load_module("snmp"); + hook_call(ldp_register_mib, master); +} + enum ldpd_process ldpd_process; #define LDP_DEFAULT_CONFIG "ldpd.conf" @@ -94,8 +118,6 @@ enum ldpd_process ldpd_process; /* Master of threads. */ struct thread_master *master; -static struct frr_daemon_info ldpd_di; - /* ldpd privileges */ static zebra_capabilities_t _caps_p [] = { @@ -1343,6 +1365,9 @@ merge_global(struct ldpd_conf *conf, struct ldpd_conf *xconf) ldpe_reset_ds_nbrs(); } + if (ldpd_process == PROC_LDP_ENGINE) + ldpe_set_config_change_time(); + conf->flags = xconf->flags; } diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h index beb625d8a2..103f4f228d 100644 --- a/ldpd/ldpd.h +++ b/ldpd/ldpd.h @@ -161,6 +161,7 @@ enum imsg_type { IMSG_RLFA_REG, IMSG_RLFA_UNREG_ALL, IMSG_RLFA_LABELS, + IMSG_AGENTX_ENABLED, }; struct ldpd_init { @@ -434,6 +435,7 @@ struct ldp_stats { uint32_t labelrel_rcvd; uint32_t labelabreq_sent; uint32_t labelabreq_rcvd; + }; struct l2vpn_if { @@ -562,6 +564,7 @@ struct ldpd_conf { uint16_t trans_pref; uint16_t wait_for_sync_interval; int flags; + time_t config_change_time; QOBJ_FIELDS }; DECLARE_QOBJ_TYPE(ldpd_conf) @@ -683,6 +686,8 @@ struct ctl_nbr { int nbr_state; struct ldp_stats stats; int flags; + uint16_t max_pdu_len; + uint16_t hold_time_remaining; }; struct ctl_rt { @@ -891,4 +896,8 @@ int ldp_zebra_send_rlfa_labels(struct zapi_rlfa_response * (__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_INTFACELOCAL)) #endif +DECLARE_HOOK(ldp_register_mib, (struct thread_master * tm), (tm)) + +extern void ldp_agentx_enabled(void); + #endif /* _LDPD_H_ */ diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c index 6a5a0750bd..d09eb2fa33 100644 --- a/ldpd/ldpe.c +++ b/ldpd/ldpe.c @@ -33,6 +33,7 @@ #include "memory.h" #include "privs.h" #include "sigevent.h" +#include "libfrr.h" static void ldpe_shutdown(void); static int ldpe_dispatch_main(struct thread *); @@ -103,15 +104,13 @@ char *pkt_ptr; /* packet buffer */ void ldpe(void) { - struct thread thread; - #ifdef HAVE_SETPROCTITLE setproctitle("ldp engine"); #endif ldpd_process = PROC_LDP_ENGINE; log_procname = log_procnames[ldpd_process]; - master = thread_master_create(NULL); + master = frr_init(); /* setup signal handler */ signal_init(master, array_size(ldpe_signals), ldpe_signals); @@ -133,9 +132,12 @@ ldpe(void) /* create base configuration */ leconf = config_new_empty(); - /* Fetch next active thread. */ + struct thread thread; while (thread_fetch(master, &thread)) thread_call(&thread); + + /* NOTREACHED */ + return; } void @@ -387,6 +389,9 @@ ldpe_dispatch_main(struct thread *thread) memcpy(&init, imsg.data, sizeof(init)); ldpe_init(&init); break; + case IMSG_AGENTX_ENABLED: + ldp_agentx_enabled(); + break; case IMSG_CLOSE_SOCKETS: af = imsg.hdr.peerid; @@ -1073,3 +1078,10 @@ ldpe_check_filter_af(int af, struct ldpd_af_conf *af_conf, if (strcmp(af_conf->acl_thello_accept_from, filter_name) == 0) ldpe_remove_dynamic_tnbrs(af); } + +void +ldpe_set_config_change_time(void) +{ + /* SNMP update time when ever there is a config change */ + leconf->config_change_time = time(NULL); +} diff --git a/ldpd/ldpe.h b/ldpd/ldpe.h index ef4702341b..9572f1ac12 100644 --- a/ldpd/ldpe.h +++ b/ldpd/ldpe.h @@ -216,6 +216,7 @@ void ldpe_nbr_ctl(struct ctl_conn *); void ldpe_ldp_sync_ctl(struct ctl_conn *); void mapping_list_add(struct mapping_head *, struct map *); void mapping_list_clr(struct mapping_head *); +void ldpe_set_config_change_time(void); /* interface.c */ struct iface *if_new(const char *); @@ -266,6 +267,8 @@ struct nbr *nbr_new(struct in_addr, int, int, union ldpd_addr *, uint32_t); void nbr_del(struct nbr *); struct nbr *nbr_find_ldpid(uint32_t); +struct nbr *nbr_get_first_ldpid(void); +struct nbr *nbr_get_next_ldpid(uint32_t); struct nbr *nbr_find_addr(int, union ldpd_addr *); struct nbr *nbr_find_peerid(uint32_t); int nbr_adj_count(struct nbr *, int); @@ -318,4 +321,6 @@ void ldpe_l2vpn_exit(struct l2vpn *); void ldpe_l2vpn_pw_init(struct l2vpn_pw *); void ldpe_l2vpn_pw_exit(struct l2vpn_pw *); +DECLARE_HOOK(ldp_nbr_state_change, (struct nbr * nbr, int old_state), (nbr, old_state)) + #endif /* _LDPE_H_ */ diff --git a/ldpd/neighbor.c b/ldpd/neighbor.c index 75deaad2c0..23c67ec1ca 100644 --- a/ldpd/neighbor.c +++ b/ldpd/neighbor.c @@ -26,6 +26,8 @@ #include "lde.h" #include "log.h" +DEFINE_HOOK(ldp_nbr_state_change, (struct nbr * nbr, int old_state), (nbr, old_state)) + static __inline int nbr_id_compare(const struct nbr *, const struct nbr *); static __inline int nbr_addr_compare(const struct nbr *, const struct nbr *); @@ -158,6 +160,8 @@ nbr_fsm(struct nbr *nbr, enum nbr_event event) &nbr->id, nbr_state_name(old_state), nbr_state_name(nbr->state)); + hook_call(ldp_nbr_state_change, nbr, old_state); + if (nbr->state == NBR_STA_OPER) { gettimeofday(&now, NULL); nbr->uptime = now.tv_sec; @@ -354,6 +358,23 @@ nbr_find_ldpid(uint32_t lsr_id) return (RB_FIND(nbr_id_head, &nbrs_by_id, &n)); } +struct nbr * +nbr_get_first_ldpid() +{ + return (RB_MIN(nbr_id_head, &nbrs_by_id)); +} + +struct nbr * +nbr_get_next_ldpid(uint32_t lsr_id) +{ + struct nbr *nbr; + nbr = nbr_find_ldpid(lsr_id); + if (nbr) + return (RB_NEXT(nbr_id_head, nbr)); + return NULL; +} + + struct nbr * nbr_find_addr(int af, union ldpd_addr *addr) { @@ -831,14 +852,20 @@ nbr_to_ctl(struct nbr *nbr) nctl.af = nbr->af; nctl.id = nbr->id; nctl.laddr = nbr->laddr; - nctl.lport = nbr->tcp->lport; + nctl.lport = nbr->tcp ? nbr->tcp->lport : 0; nctl.raddr = nbr->raddr; - nctl.rport = nbr->tcp->rport; + nctl.rport = nbr->tcp ? nbr->tcp->rport : 0; nctl.auth_method = nbr->auth.method; nctl.holdtime = nbr->keepalive; nctl.nbr_state = nbr->state; nctl.stats = nbr->stats; nctl.flags = nbr->flags; + nctl.max_pdu_len = nbr->max_pdu_len; + if (nbr->keepalive_timer) + nctl.hold_time_remaining = + thread_timer_remain_second(nbr->keepalive_timer); + else + nctl.hold_time_remaining = 0; gettimeofday(&now, NULL); if (nbr->state == NBR_STA_OPER) { diff --git a/ldpd/subdir.am b/ldpd/subdir.am index d89d18341d..b01d414de8 100644 --- a/ldpd/subdir.am +++ b/ldpd/subdir.am @@ -41,6 +41,10 @@ ldpd_libldp_a_SOURCES = \ ldpd/util.c \ # end +if SNMP +module_LTLIBRARIES += ldpd/ldpd_snmp.la +endif + clippy_scan += \ ldpd/ldp_vty_cmds.c \ # end @@ -59,3 +63,8 @@ noinst_HEADERS += \ ldpd_ldpd_SOURCES = ldpd/ldpd.c ldpd_ldpd_LDADD = ldpd/libldp.a lib/libfrr.la $(LIBCAP) + +ldpd_ldpd_snmp_la_SOURCES = ldpd/ldp_snmp.c +ldpd_ldpd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu99 +ldpd_ldpd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic +ldpd_ldpd_snmp_la_LIBADD = lib/libfrrsnmp.la diff --git a/tests/topotests/ldp-snmp/ce1/zebra.conf b/tests/topotests/ldp-snmp/ce1/zebra.conf new file mode 100644 index 0000000000..6f165e2724 --- /dev/null +++ b/tests/topotests/ldp-snmp/ce1/zebra.conf @@ -0,0 +1,12 @@ +log file zebra.log +! +hostname ce1 +! +interface ce1-eth0 + ip address 172.16.1.1/24 + no link-detect +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/ldp-snmp/ce2/zebra.conf b/tests/topotests/ldp-snmp/ce2/zebra.conf new file mode 100644 index 0000000000..ac02d0f9a4 --- /dev/null +++ b/tests/topotests/ldp-snmp/ce2/zebra.conf @@ -0,0 +1,12 @@ +log file zebra.log +! +hostname ce2 +! +interface ce2-eth0 + ip address 172.16.1.2/24 + no link-detect +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/ldp-snmp/ce3/zebra.conf b/tests/topotests/ldp-snmp/ce3/zebra.conf new file mode 100644 index 0000000000..c6a5824d15 --- /dev/null +++ b/tests/topotests/ldp-snmp/ce3/zebra.conf @@ -0,0 +1,12 @@ +log file zebra.log +! +hostname ce3 +! +interface ce3-eth0 + ip address 172.16.1.3/24 + no link-detect +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/ldp-snmp/r1/isisd.conf b/tests/topotests/ldp-snmp/r1/isisd.conf new file mode 100644 index 0000000000..da2970d94e --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/isisd.conf @@ -0,0 +1,27 @@ +hostname r1 +log file isisd.log +debug isis adj-packets +debug isis events +debug isis update-packets +debug isis ldp-sync +! +router isis 1 + lsp-gen-interval 2 + net 10.0000.0000.0000.0000.0000.0000.0000.0000.0001.00 + metric-style wide + redistribute ipv4 connected level-1 + redistribute ipv6 connected level-1 + mpls ldp-sync +! +interface r1-eth1 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis circuit-type level-1 +! +interface r1-eth2 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis circuit-type level-1 +! diff --git a/tests/topotests/ldp-snmp/r1/ldpd.conf b/tests/topotests/ldp-snmp/r1/ldpd.conf new file mode 100644 index 0000000000..01fc039b09 --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/ldpd.conf @@ -0,0 +1,35 @@ +hostname r1 +log file ldpd.log +! +debug mpls ldp zebra +debug mpls ldp event +debug mpls ldp errors +debug mpls ldp sync +! +mpls ldp + router-id 1.1.1.1 + ! + address-family ipv4 + discovery transport-address 1.1.1.1 + label local allocate host-routes + ! + ttl-security disable + ! + interface r1-eth1 + ! + interface r1-eth2 + ! + ! +! +l2vpn CUST_A type vpls + member interface r1-eth0 + ! + member pseudowire r1-mpw0 + neighbor lsr-id 2.2.2.2 + pw-id 100 + ! +! +line vty +! +agentx +! diff --git a/tests/topotests/ldp-snmp/r1/show_ip_route.ref b/tests/topotests/ldp-snmp/r1/show_ip_route.ref new file mode 100644 index 0000000000..b1a55ba103 --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/show_ip_route.ref @@ -0,0 +1,134 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"lo", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "distance":115, + "metric":10, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"r1-eth1", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "distance":115, + "metric":10, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.3", + "afi":"ipv4", + "interfaceName":"r1-eth2", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":10, + "nexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"r1-eth1" + } + ] + }, + { + "prefix":"10.0.1.0\/24", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"r1-eth1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":10, + "nexthops":[ + { + "ip":"10.0.2.3", + "afi":"ipv4", + "interfaceName":"r1-eth2" + } + ] + }, + { + "prefix":"10.0.2.0\/24", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"r1-eth2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "distance":115, + "metric":10, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"r1-eth1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.3", + "afi":"ipv4", + "interfaceName":"r1-eth2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ldp-snmp/r1/show_isis_interface_detail.ref b/tests/topotests/ldp-snmp/r1/show_isis_interface_detail.ref new file mode 100644 index 0000000000..d8fb27af8c --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/show_isis_interface_detail.ref @@ -0,0 +1,16 @@ +{ + "1": { + "r1-eth1": [ + { + "level": "Level-1", + "metric": "10" + } + ], + "r1-eth2": [ + { + "level": "Level-1", + "metric": "10" + } + ] + } +} diff --git a/tests/topotests/ldp-snmp/r1/show_isis_interface_detail_r1_eth1_shutdown.ref b/tests/topotests/ldp-snmp/r1/show_isis_interface_detail_r1_eth1_shutdown.ref new file mode 100644 index 0000000000..f77d65ebc1 --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/show_isis_interface_detail_r1_eth1_shutdown.ref @@ -0,0 +1,16 @@ +{ + "1": { + "r1-eth1": [ + { + "level": "Level-1", + "metric": "16777214" + } + ], + "r1-eth2": [ + { + "level": "Level-1", + "metric": "10" + } + ] + } +} diff --git a/tests/topotests/ldp-snmp/r1/show_isis_interface_detail_r2_eth1_shutdown.ref b/tests/topotests/ldp-snmp/r1/show_isis_interface_detail_r2_eth1_shutdown.ref new file mode 100644 index 0000000000..f77d65ebc1 --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/show_isis_interface_detail_r2_eth1_shutdown.ref @@ -0,0 +1,16 @@ +{ + "1": { + "r1-eth1": [ + { + "level": "Level-1", + "metric": "16777214" + } + ], + "r1-eth2": [ + { + "level": "Level-1", + "metric": "10" + } + ] + } +} diff --git a/tests/topotests/ldp-snmp/r1/show_isis_ldp_sync.ref b/tests/topotests/ldp-snmp/r1/show_isis_ldp_sync.ref new file mode 100644 index 0000000000..b699e8c145 --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/show_isis_ldp_sync.ref @@ -0,0 +1,13 @@ +{ + "r1-eth1":{ + "ldpIgpSyncEnabled":true, + "holdDownTimeInSec":0, + "ldpIgpSyncState":"Sync achieved" + }, + "r1-eth2":{ + "ldpIgpSyncEnabled":true, + "holdDownTimeInSec":0, + "ldpIgpSyncState":"Sync achieved" + } + +} diff --git a/tests/topotests/ldp-snmp/r1/show_isis_ldp_sync_r1_eth1_shutdown.ref b/tests/topotests/ldp-snmp/r1/show_isis_ldp_sync_r1_eth1_shutdown.ref new file mode 100644 index 0000000000..c28cd4cc7d --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/show_isis_ldp_sync_r1_eth1_shutdown.ref @@ -0,0 +1,11 @@ +{ + "r1-eth1":{ + "Interface":true + }, + "r1-eth2":{ + "ldpIgpSyncEnabled":true, + "holdDownTimeInSec":0, + "ldpIgpSyncState":"Sync achieved" + } + +} diff --git a/tests/topotests/ldp-snmp/r1/show_isis_ldp_sync_r2_eth1_shutdown.ref b/tests/topotests/ldp-snmp/r1/show_isis_ldp_sync_r2_eth1_shutdown.ref new file mode 100644 index 0000000000..c63bbea77f --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/show_isis_ldp_sync_r2_eth1_shutdown.ref @@ -0,0 +1,13 @@ +{ + "r1-eth1":{ + "ldpIgpSyncEnabled":true, + "holdDownTimeInSec":0, + "ldpIgpSyncState":"Sync not achieved" + }, + "r1-eth2":{ + "ldpIgpSyncEnabled":true, + "holdDownTimeInSec":0, + "ldpIgpSyncState":"Sync achieved" + } + +} diff --git a/tests/topotests/ldp-snmp/r1/show_l2vpn_binding.ref b/tests/topotests/ldp-snmp/r1/show_l2vpn_binding.ref new file mode 100644 index 0000000000..b3de7e2c66 --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/show_l2vpn_binding.ref @@ -0,0 +1,16 @@ +{ + "2.2.2.2: 100":{ + "destination":"2.2.2.2", + "vcId":100, + "localLabel":16, + "localControlWord":1, + "localVcType":"Ethernet", + "localGroupID":0, + "localIfMtu":1500, + "remoteLabel":16, + "remoteControlWord":1, + "remoteVcType":"Ethernet", + "remoteGroupID":0, + "remoteIfMtu":1500 + } +} diff --git a/tests/topotests/ldp-snmp/r1/show_l2vpn_vc.ref b/tests/topotests/ldp-snmp/r1/show_l2vpn_vc.ref new file mode 100644 index 0000000000..29e9df1089 --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/show_l2vpn_vc.ref @@ -0,0 +1,8 @@ +{ + "r1-mpw0":{ + "peerId":"2.2.2.2", + "vcId":100, + "VpnName":"CUST_A", + "status":"up" + } +} diff --git a/tests/topotests/ldp-snmp/r1/show_ldp_binding.ref b/tests/topotests/ldp-snmp/r1/show_ldp_binding.ref new file mode 100644 index 0000000000..b3a12ec53f --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/show_ldp_binding.ref @@ -0,0 +1,44 @@ +{ + "bindings":[ + { + "addressFamily":"ipv4", + "prefix":"1.1.1.1/32", + "neighborId":"2.2.2.2", + "localLabel":"imp-null", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"1.1.1.1/32", + "neighborId":"3.3.3.3", + "localLabel":"imp-null", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"2.2.2.2/32", + "neighborId":"2.2.2.2", + "remoteLabel":"imp-null", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"2.2.2.2/32", + "neighborId":"3.3.3.3", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"3.3.3.3/32", + "neighborId":"2.2.2.2", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"3.3.3.3/32", + "neighborId":"3.3.3.3", + "remoteLabel":"imp-null", + "inUse":1 + } + ] +} diff --git a/tests/topotests/ldp-snmp/r1/show_ldp_discovery.ref b/tests/topotests/ldp-snmp/r1/show_ldp_discovery.ref new file mode 100644 index 0000000000..9301e60c67 --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/show_ldp_discovery.ref @@ -0,0 +1,25 @@ +{ + "adjacencies":[ + { + "addressFamily":"ipv4", + "neighborId":"2.2.2.2", + "type":"link", + "interface":"r1-eth1", + "helloHoldtime":15 + }, + { + "addressFamily":"ipv4", + "neighborId":"2.2.2.2", + "type":"targeted", + "peer":"2.2.2.2", + "helloHoldtime":45 + }, + { + "addressFamily":"ipv4", + "neighborId":"3.3.3.3", + "type":"link", + "interface":"r1-eth2", + "helloHoldtime":15 + } + ] +} diff --git a/tests/topotests/ldp-snmp/r1/show_ldp_igp_sync.ref b/tests/topotests/ldp-snmp/r1/show_ldp_igp_sync.ref new file mode 100644 index 0000000000..54d015fef9 --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/show_ldp_igp_sync.ref @@ -0,0 +1,16 @@ +{ + "r1-eth1":{ + "state":"labelExchangeComplete", + "waitTime":10, + "waitTimeRemaining":0, + "timerRunning":false, + "peerLdpId":"2.2.2.2" + }, + "r1-eth2":{ + "state":"labelExchangeComplete", + "waitTime":10, + "waitTimeRemaining":0, + "timerRunning":false, + "peerLdpId":"3.3.3.3" + } +} diff --git a/tests/topotests/ldp-snmp/r1/show_ldp_igp_sync_r1_eth1_shutdown.ref b/tests/topotests/ldp-snmp/r1/show_ldp_igp_sync_r1_eth1_shutdown.ref new file mode 100644 index 0000000000..2232069f68 --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/show_ldp_igp_sync_r1_eth1_shutdown.ref @@ -0,0 +1,16 @@ +{ + "r1-eth1":{ + "state":"labelExchangeNotComplete", + "waitTime":10, + "waitTimeRemaining":0, + "timerRunning":false, + "peerLdpId":"" + }, + "r1-eth2":{ + "state":"labelExchangeComplete", + "waitTime":10, + "waitTimeRemaining":0, + "timerRunning":false, + "peerLdpId":"3.3.3.3" + } +} diff --git a/tests/topotests/ldp-snmp/r1/show_ldp_neighbor.ref b/tests/topotests/ldp-snmp/r1/show_ldp_neighbor.ref new file mode 100644 index 0000000000..40d8ebeb90 --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/show_ldp_neighbor.ref @@ -0,0 +1,16 @@ +{ + "neighbors":[ + { + "addressFamily":"ipv4", + "neighborId":"2.2.2.2", + "state":"OPERATIONAL", + "transportAddress":"2.2.2.2" + }, + { + "addressFamily":"ipv4", + "neighborId":"3.3.3.3", + "state":"OPERATIONAL", + "transportAddress":"3.3.3.3" + } + ] +} diff --git a/tests/topotests/ldp-snmp/r1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/ldp-snmp/r1/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 0000000000..6138d03672 --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,42 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "r1-eth1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "neighbor-extended-circuit-id": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "r1-eth2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "neighbor-extended-circuit-id": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/ldp-snmp/r1/snmpd.conf b/tests/topotests/ldp-snmp/r1/snmpd.conf new file mode 100644 index 0000000000..b37911da36 --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/snmpd.conf @@ -0,0 +1,15 @@ +agentAddress udp:1.1.1.1:161 + +com2sec public 1.1.1.1 public + +group public_group v1 public +group public_group v2c public + +access public_group "" any noauth prefix all all none + +view all included .1 + +iquerySecName frr +rouser frr + +master agentx diff --git a/tests/topotests/ldp-snmp/r1/zebra.conf b/tests/topotests/ldp-snmp/r1/zebra.conf new file mode 100644 index 0000000000..ea047355ad --- /dev/null +++ b/tests/topotests/ldp-snmp/r1/zebra.conf @@ -0,0 +1,29 @@ +log file zebra.log +! +hostname r1 +! +debug zebra kernel +debug zebra rib detailed +debug zebra dplane detailed +debug zebra nht +debug zebra pseudowires +debug zebra mpls +! +interface lo + ip address 1.1.1.1/32 +! +interface r1-eth0 + description to s1 +! +interface r1-eth1 + description to s4 + ip address 10.0.1.1/24 +! +interface r1-eth2 + description to s5 + ip address 10.0.2.1/24 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/ldp-snmp/r2/isisd.conf b/tests/topotests/ldp-snmp/r2/isisd.conf new file mode 100644 index 0000000000..b29a2b93ee --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/isisd.conf @@ -0,0 +1,28 @@ +hostname r2 +log file isisd.log +debug isis adj-packets +debug isis events +debug isis update-packets +debug isis ldp-sync +! +router isis 1 + lsp-gen-interval 2 + net 10.0000.0000.0000.0000.0000.0000.0000.0000.0002.00 + metric-style wide + redistribute ipv4 connected level-1 + redistribute ipv6 connected level-1 + mpls ldp-sync +! +interface r2-eth1 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis circuit-type level-1 +! +interface r2-eth2 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis circuit-type level-1 + no isis mpls ldp-sync +! diff --git a/tests/topotests/ldp-snmp/r2/ldpd.conf b/tests/topotests/ldp-snmp/r2/ldpd.conf new file mode 100644 index 0000000000..c93e1a6ac5 --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/ldpd.conf @@ -0,0 +1,35 @@ +hostname r2 +log file ldpd.log +! +debug mpls ldp zebra +debug mpls ldp event +debug mpls ldp errors +debug mpls ldp sync +! +mpls ldp + router-id 2.2.2.2 + ! + address-family ipv4 + discovery transport-address 2.2.2.2 + label local allocate host-routes + ! + ttl-security disable + ! + interface r2-eth1 + ! + interface r2-eth2 + ! + ! +! +l2vpn CUST_A type vpls + member interface r2-eth0 + ! + member pseudowire r2-mpw0 + neighbor lsr-id 1.1.1.1 + pw-id 100 + ! +! +line vty +! +!agentx +! diff --git a/tests/topotests/ldp-snmp/r2/ospfd.conf b/tests/topotests/ldp-snmp/r2/ospfd.conf new file mode 100644 index 0000000000..f93f6aed56 --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/ospfd.conf @@ -0,0 +1,19 @@ +hostname r2 +log file ospfd.log +debug ospf zebra interface +debug ospf ldp-sync +! +router ospf + router-id 2.2.2.2 + network 0.0.0.0/0 area 0 + mpls ldp-sync + mpls ldp-sync holddown 50 +! +interface r2-eth1 + ip ospf network point-to-point + ip ospf mpls ldp-sync holddown 300 +! +interface r2-eth2 + ip ospf network point-to-point + no ip ospf mpls ldp-sync +! diff --git a/tests/topotests/ldp-snmp/r2/show_ip_route.ref b/tests/topotests/ldp-snmp/r2/show_ip_route.ref new file mode 100644 index 0000000000..04f141aba4 --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/show_ip_route.ref @@ -0,0 +1,134 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "distance":115, + "metric":10, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"r2-eth1", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"lo", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "distance":115, + "metric":10, + "nexthops":[ + { + "fib":true, + "ip":"10.0.3.3", + "afi":"ipv4", + "interfaceName":"r2-eth2", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":10, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"r2-eth1" + } + ] + }, + { + "prefix":"10.0.1.0\/24", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"r2-eth1", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "distance":115, + "metric":10, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"r2-eth1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.3", + "afi":"ipv4", + "interfaceName":"r2-eth2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":10, + "nexthops":[ + { + "ip":"10.0.3.3", + "afi":"ipv4", + "interfaceName":"r2-eth2" + } + ] + }, + { + "prefix":"10.0.3.0\/24", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"r2-eth2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ldp-snmp/r2/show_isis_interface_detail.ref b/tests/topotests/ldp-snmp/r2/show_isis_interface_detail.ref new file mode 100644 index 0000000000..844aa9402a --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/show_isis_interface_detail.ref @@ -0,0 +1,16 @@ +{ + "1": { + "r2-eth1": [ + { + "level": "Level-1", + "metric": "10" + } + ], + "r2-eth2": [ + { + "level": "Level-1", + "metric": "10" + } + ] + } +} diff --git a/tests/topotests/ldp-snmp/r2/show_isis_interface_detail_r1_eth1_shutdown.ref b/tests/topotests/ldp-snmp/r2/show_isis_interface_detail_r1_eth1_shutdown.ref new file mode 100644 index 0000000000..821ec70ba5 --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/show_isis_interface_detail_r1_eth1_shutdown.ref @@ -0,0 +1,16 @@ +{ + "1": { + "r2-eth1": [ + { + "level": "Level-1", + "metric": "16777214" + } + ], + "r2-eth2": [ + { + "level": "Level-1", + "metric": "10" + } + ] + } +} diff --git a/tests/topotests/ldp-snmp/r2/show_isis_interface_detail_r2_eth1_shutdown.ref b/tests/topotests/ldp-snmp/r2/show_isis_interface_detail_r2_eth1_shutdown.ref new file mode 100644 index 0000000000..821ec70ba5 --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/show_isis_interface_detail_r2_eth1_shutdown.ref @@ -0,0 +1,16 @@ +{ + "1": { + "r2-eth1": [ + { + "level": "Level-1", + "metric": "16777214" + } + ], + "r2-eth2": [ + { + "level": "Level-1", + "metric": "10" + } + ] + } +} diff --git a/tests/topotests/ldp-snmp/r2/show_isis_ldp_sync.ref b/tests/topotests/ldp-snmp/r2/show_isis_ldp_sync.ref new file mode 100644 index 0000000000..433d89bd16 --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/show_isis_ldp_sync.ref @@ -0,0 +1,13 @@ +{ + "r2-eth1":{ + "ldpIgpSyncEnabled":true, + "holdDownTimeInSec":0, + "ldpIgpSyncState":"Sync achieved" + }, + "r2-eth2":{ + "ldpIgpSyncEnabled":false, + "holdDownTimeInSec":0, + "ldpIgpSyncState":"Sync not required" + } + +} diff --git a/tests/topotests/ldp-snmp/r2/show_isis_ldp_sync_r1_eth1_shutdown.ref b/tests/topotests/ldp-snmp/r2/show_isis_ldp_sync_r1_eth1_shutdown.ref new file mode 100644 index 0000000000..2f3eae47c8 --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/show_isis_ldp_sync_r1_eth1_shutdown.ref @@ -0,0 +1,13 @@ +{ + "r2-eth1":{ + "ldpIgpSyncEnabled":true, + "holdDownTimeInSec":0, + "ldpIgpSyncState":"Sync not achieved" + }, + "r2-eth2":{ + "ldpIgpSyncEnabled":false, + "holdDownTimeInSec":0, + "ldpIgpSyncState":"Sync not required" + } + +} diff --git a/tests/topotests/ldp-snmp/r2/show_isis_ldp_sync_r2_eth1_shutdown.ref b/tests/topotests/ldp-snmp/r2/show_isis_ldp_sync_r2_eth1_shutdown.ref new file mode 100644 index 0000000000..c3d97a3c73 --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/show_isis_ldp_sync_r2_eth1_shutdown.ref @@ -0,0 +1,11 @@ +{ + "r2-eth1":{ + "Interface":true + }, + "r2-eth2":{ + "ldpIgpSyncEnabled":false, + "holdDownTimeInSec":0, + "ldpIgpSyncState":"Sync not required" + } + +} diff --git a/tests/topotests/ldp-snmp/r2/show_l2vpn_binding.ref b/tests/topotests/ldp-snmp/r2/show_l2vpn_binding.ref new file mode 100644 index 0000000000..42c5a1cbd9 --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/show_l2vpn_binding.ref @@ -0,0 +1,16 @@ +{ + "1.1.1.1: 100":{ + "destination":"1.1.1.1", + "vcId":100, + "localLabel":16, + "localControlWord":1, + "localVcType":"Ethernet", + "localGroupID":0, + "localIfMtu":1500, + "remoteLabel":16, + "remoteControlWord":1, + "remoteVcType":"Ethernet", + "remoteGroupID":0, + "remoteIfMtu":1500 + } +} diff --git a/tests/topotests/ldp-snmp/r2/show_l2vpn_vc.ref b/tests/topotests/ldp-snmp/r2/show_l2vpn_vc.ref new file mode 100644 index 0000000000..942ed23a1e --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/show_l2vpn_vc.ref @@ -0,0 +1,8 @@ +{ + "r2-mpw0":{ + "peerId":"1.1.1.1", + "vcId":100, + "VpnName":"CUST_A", + "status":"up" + } +} diff --git a/tests/topotests/ldp-snmp/r2/show_ldp_binding.ref b/tests/topotests/ldp-snmp/r2/show_ldp_binding.ref new file mode 100644 index 0000000000..c641fb47e6 --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/show_ldp_binding.ref @@ -0,0 +1,44 @@ +{ + "bindings":[ + { + "addressFamily":"ipv4", + "prefix":"1.1.1.1/32", + "neighborId":"1.1.1.1", + "remoteLabel":"imp-null", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"1.1.1.1/32", + "neighborId":"3.3.3.3", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"2.2.2.2/32", + "neighborId":"1.1.1.1", + "localLabel":"imp-null", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"2.2.2.2/32", + "neighborId":"3.3.3.3", + "localLabel":"imp-null", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"3.3.3.3/32", + "neighborId":"1.1.1.1", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"3.3.3.3/32", + "neighborId":"3.3.3.3", + "remoteLabel":"imp-null", + "inUse":1 + } + ] +} diff --git a/tests/topotests/ldp-snmp/r2/show_ldp_discovery.ref b/tests/topotests/ldp-snmp/r2/show_ldp_discovery.ref new file mode 100644 index 0000000000..26801acade --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/show_ldp_discovery.ref @@ -0,0 +1,25 @@ +{ + "adjacencies":[ + { + "addressFamily":"ipv4", + "neighborId":"1.1.1.1", + "type":"link", + "interface":"r2-eth1", + "helloHoldtime":15 + }, + { + "addressFamily":"ipv4", + "neighborId":"1.1.1.1", + "type":"targeted", + "peer":"1.1.1.1", + "helloHoldtime":45 + }, + { + "addressFamily":"ipv4", + "neighborId":"3.3.3.3", + "type":"link", + "interface":"r2-eth2", + "helloHoldtime":15 + } + ] +} diff --git a/tests/topotests/ldp-snmp/r2/show_ldp_igp_sync.ref b/tests/topotests/ldp-snmp/r2/show_ldp_igp_sync.ref new file mode 100644 index 0000000000..f2b24d7d62 --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/show_ldp_igp_sync.ref @@ -0,0 +1,16 @@ +{ + "r2-eth1":{ + "state":"labelExchangeComplete", + "waitTime":10, + "waitTimeRemaining":0, + "timerRunning":false, + "peerLdpId":"1.1.1.1" + }, + "r2-eth2":{ + "state":"labelExchangeComplete", + "waitTime":10, + "waitTimeRemaining":0, + "timerRunning":false, + "peerLdpId":"3.3.3.3" + } +} diff --git a/tests/topotests/ldp-snmp/r2/show_ldp_igp_sync_r1_eth1_shutdown.ref b/tests/topotests/ldp-snmp/r2/show_ldp_igp_sync_r1_eth1_shutdown.ref new file mode 100644 index 0000000000..b5508dd35c --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/show_ldp_igp_sync_r1_eth1_shutdown.ref @@ -0,0 +1,16 @@ +{ + "r2-eth1":{ + "state":"labelExchangeNotComplete", + "waitTime":10, + "waitTimeRemaining":0, + "timerRunning":false, + "peerLdpId":"" + }, + "r2-eth2":{ + "state":"labelExchangeComplete", + "waitTime":10, + "waitTimeRemaining":0, + "timerRunning":false, + "peerLdpId":"3.3.3.3" + } +} diff --git a/tests/topotests/ldp-snmp/r2/show_ldp_igp_sync_r2_eth1_shutdown.ref b/tests/topotests/ldp-snmp/r2/show_ldp_igp_sync_r2_eth1_shutdown.ref new file mode 100644 index 0000000000..f2b24d7d62 --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/show_ldp_igp_sync_r2_eth1_shutdown.ref @@ -0,0 +1,16 @@ +{ + "r2-eth1":{ + "state":"labelExchangeComplete", + "waitTime":10, + "waitTimeRemaining":0, + "timerRunning":false, + "peerLdpId":"1.1.1.1" + }, + "r2-eth2":{ + "state":"labelExchangeComplete", + "waitTime":10, + "waitTimeRemaining":0, + "timerRunning":false, + "peerLdpId":"3.3.3.3" + } +} diff --git a/tests/topotests/ldp-snmp/r2/show_ldp_neighbor.ref b/tests/topotests/ldp-snmp/r2/show_ldp_neighbor.ref new file mode 100644 index 0000000000..eed35289ea --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/show_ldp_neighbor.ref @@ -0,0 +1,16 @@ +{ + "neighbors":[ + { + "addressFamily":"ipv4", + "neighborId":"1.1.1.1", + "state":"OPERATIONAL", + "transportAddress":"1.1.1.1" + }, + { + "addressFamily":"ipv4", + "neighborId":"3.3.3.3", + "state":"OPERATIONAL", + "transportAddress":"3.3.3.3" + } + ] +} diff --git a/tests/topotests/ldp-snmp/r2/show_yang_interface_isis_adjacencies.ref b/tests/topotests/ldp-snmp/r2/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 0000000000..4dd6ddd76b --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,42 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "r2-eth1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0001", + "neighbor-extended-circuit-id": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "r2-eth2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0003", + "neighbor-extended-circuit-id": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/ldp-snmp/r2/snmpd.conf b/tests/topotests/ldp-snmp/r2/snmpd.conf new file mode 100644 index 0000000000..0f779b8b91 --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/snmpd.conf @@ -0,0 +1,15 @@ +agentAddress udp:2.2.2.2:161 + +com2sec public 2.2.2.2 public + +group public_group v1 public +group public_group v2c public + +access public_group "" any noauth prefix all all none + +view all included .1 + +iquerySecName frr +rouser frr + +master agentx diff --git a/tests/topotests/ldp-snmp/r2/zebra.conf b/tests/topotests/ldp-snmp/r2/zebra.conf new file mode 100644 index 0000000000..c244442876 --- /dev/null +++ b/tests/topotests/ldp-snmp/r2/zebra.conf @@ -0,0 +1,28 @@ +log file zebra.log +! +hostname r2 +! +debug zebra rib detailed +debug zebra dplane detailed +debug zebra kernel +debug zebra nht +debug zebra pseudowires +! +interface lo + ip address 2.2.2.2/32 +! +interface r2-eth0 + description to s2 +! +interface r2-eth1 + description to s4 + ip address 10.0.1.2/24 +! +interface r2-eth2 + description to s6 + ip address 10.0.3.2/24 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/ldp-snmp/r3/isisd.conf b/tests/topotests/ldp-snmp/r3/isisd.conf new file mode 100644 index 0000000000..4c8499f23d --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/isisd.conf @@ -0,0 +1,29 @@ +hostname r3 +log file isisd.log +debug isis adj-packets +debug isis events +debug isis update-packets +debug isis ldp-sync +! +router isis 1 + lsp-gen-interval 2 + net 10.0000.0000.0000.0000.0000.0000.0000.0000.0003.00 + metric-style wide + redistribute ipv4 connected level-1 + redistribute ipv6 connected level-1 + mpls ldp-sync + mpls ldp-sync holddown 50 +! +interface r3-eth1 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis circuit-type level-1 + no isis mpls ldp-sync +! +interface r3-eth2 + ip router isis 1 + ipv6 router isis 1 + isis network point-to-point + isis circuit-type level-1 +! diff --git a/tests/topotests/ldp-snmp/r3/ldpd.conf b/tests/topotests/ldp-snmp/r3/ldpd.conf new file mode 100644 index 0000000000..b7eeb258f1 --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/ldpd.conf @@ -0,0 +1,27 @@ +hostname r3 +log file ldpd.log +! +debug mpls ldp zebra +debug mpls ldp event +debug mpls ldp errors +debug mpls ldp sync +! +mpls ldp + router-id 3.3.3.3 + ! + address-family ipv4 + discovery transport-address 3.3.3.3 + label local allocate host-routes + ! + ttl-security disable + ! + interface r3-eth1 + ! + interface r3-eth2 + ! + ! +! +line vty +! +!agentx +! diff --git a/tests/topotests/ldp-snmp/r3/show_ip_route.ref b/tests/topotests/ldp-snmp/r3/show_ip_route.ref new file mode 100644 index 0000000000..22504046ed --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/show_ip_route.ref @@ -0,0 +1,134 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "distance":115, + "metric":10, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.1", + "afi":"ipv4", + "interfaceName":"r3-eth1", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "distance":115, + "metric":10, + "nexthops":[ + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"r3-eth2", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"lo", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "distance":115, + "metric":10, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.1", + "afi":"ipv4", + "interfaceName":"r3-eth1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"r3-eth2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":10, + "nexthops":[ + { + "ip":"10.0.2.1", + "afi":"ipv4", + "interfaceName":"r3-eth1" + } + ] + }, + { + "prefix":"10.0.2.0\/24", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"r3-eth1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":10, + "nexthops":[ + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"r3-eth2" + } + ] + }, + { + "prefix":"10.0.3.0\/24", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"r3-eth2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ldp-snmp/r3/show_isis_interface_detail.ref b/tests/topotests/ldp-snmp/r3/show_isis_interface_detail.ref new file mode 100644 index 0000000000..e323f61f25 --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/show_isis_interface_detail.ref @@ -0,0 +1,16 @@ +{ + "1": { + "r3-eth1": [ + { + "level": "Level-1", + "metric": "10" + } + ], + "r3-eth2": [ + { + "level": "Level-1", + "metric": "10" + } + ] + } +} diff --git a/tests/topotests/ldp-snmp/r3/show_isis_interface_detail_r1_eth1_shutdown.ref b/tests/topotests/ldp-snmp/r3/show_isis_interface_detail_r1_eth1_shutdown.ref new file mode 100644 index 0000000000..e323f61f25 --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/show_isis_interface_detail_r1_eth1_shutdown.ref @@ -0,0 +1,16 @@ +{ + "1": { + "r3-eth1": [ + { + "level": "Level-1", + "metric": "10" + } + ], + "r3-eth2": [ + { + "level": "Level-1", + "metric": "10" + } + ] + } +} diff --git a/tests/topotests/ldp-snmp/r3/show_isis_interface_detail_r2_eth1_shutdown.ref b/tests/topotests/ldp-snmp/r3/show_isis_interface_detail_r2_eth1_shutdown.ref new file mode 100644 index 0000000000..e323f61f25 --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/show_isis_interface_detail_r2_eth1_shutdown.ref @@ -0,0 +1,16 @@ +{ + "1": { + "r3-eth1": [ + { + "level": "Level-1", + "metric": "10" + } + ], + "r3-eth2": [ + { + "level": "Level-1", + "metric": "10" + } + ] + } +} diff --git a/tests/topotests/ldp-snmp/r3/show_isis_ldp_sync.ref b/tests/topotests/ldp-snmp/r3/show_isis_ldp_sync.ref new file mode 100644 index 0000000000..9cb70a4758 --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/show_isis_ldp_sync.ref @@ -0,0 +1,13 @@ +{ + "r3-eth1":{ + "ldpIgpSyncEnabled":false, + "holdDownTimeInSec":50, + "ldpIgpSyncState":"Sync not required" + }, + "r3-eth2":{ + "ldpIgpSyncEnabled":true, + "holdDownTimeInSec":50, + "ldpIgpSyncState":"Sync achieved" + } + +} diff --git a/tests/topotests/ldp-snmp/r3/show_isis_ldp_sync_r1_eth1_shutdown.ref b/tests/topotests/ldp-snmp/r3/show_isis_ldp_sync_r1_eth1_shutdown.ref new file mode 100644 index 0000000000..9cb70a4758 --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/show_isis_ldp_sync_r1_eth1_shutdown.ref @@ -0,0 +1,13 @@ +{ + "r3-eth1":{ + "ldpIgpSyncEnabled":false, + "holdDownTimeInSec":50, + "ldpIgpSyncState":"Sync not required" + }, + "r3-eth2":{ + "ldpIgpSyncEnabled":true, + "holdDownTimeInSec":50, + "ldpIgpSyncState":"Sync achieved" + } + +} diff --git a/tests/topotests/ldp-snmp/r3/show_isis_ldp_sync_r2_eth1_shutdown.ref b/tests/topotests/ldp-snmp/r3/show_isis_ldp_sync_r2_eth1_shutdown.ref new file mode 100644 index 0000000000..9cb70a4758 --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/show_isis_ldp_sync_r2_eth1_shutdown.ref @@ -0,0 +1,13 @@ +{ + "r3-eth1":{ + "ldpIgpSyncEnabled":false, + "holdDownTimeInSec":50, + "ldpIgpSyncState":"Sync not required" + }, + "r3-eth2":{ + "ldpIgpSyncEnabled":true, + "holdDownTimeInSec":50, + "ldpIgpSyncState":"Sync achieved" + } + +} diff --git a/tests/topotests/ldp-snmp/r3/show_l2vpn_binding.ref b/tests/topotests/ldp-snmp/r3/show_l2vpn_binding.ref new file mode 100644 index 0000000000..2c63c08510 --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/show_l2vpn_binding.ref @@ -0,0 +1,2 @@ +{ +} diff --git a/tests/topotests/ldp-snmp/r3/show_l2vpn_vc.ref b/tests/topotests/ldp-snmp/r3/show_l2vpn_vc.ref new file mode 100644 index 0000000000..2c63c08510 --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/show_l2vpn_vc.ref @@ -0,0 +1,2 @@ +{ +} diff --git a/tests/topotests/ldp-snmp/r3/show_ldp_binding.ref b/tests/topotests/ldp-snmp/r3/show_ldp_binding.ref new file mode 100644 index 0000000000..e54bd6e755 --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/show_ldp_binding.ref @@ -0,0 +1,44 @@ +{ + "bindings":[ + { + "addressFamily":"ipv4", + "prefix":"1.1.1.1/32", + "neighborId":"1.1.1.1", + "remoteLabel":"imp-null", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"1.1.1.1/32", + "neighborId":"2.2.2.2", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"2.2.2.2/32", + "neighborId":"1.1.1.1", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"2.2.2.2/32", + "neighborId":"2.2.2.2", + "remoteLabel":"imp-null", + "inUse":1 + }, + { + "addressFamily":"ipv4", + "prefix":"3.3.3.3/32", + "neighborId":"1.1.1.1", + "localLabel":"imp-null", + "inUse":0 + }, + { + "addressFamily":"ipv4", + "prefix":"3.3.3.3/32", + "neighborId":"2.2.2.2", + "localLabel":"imp-null", + "inUse":0 + } + ] +} diff --git a/tests/topotests/ldp-snmp/r3/show_ldp_discovery.ref b/tests/topotests/ldp-snmp/r3/show_ldp_discovery.ref new file mode 100644 index 0000000000..42fa98d4da --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/show_ldp_discovery.ref @@ -0,0 +1,18 @@ +{ + "adjacencies":[ + { + "addressFamily":"ipv4", + "neighborId":"1.1.1.1", + "type":"link", + "interface":"r3-eth1", + "helloHoldtime":15 + }, + { + "addressFamily":"ipv4", + "neighborId":"2.2.2.2", + "type":"link", + "interface":"r3-eth2", + "helloHoldtime":15 + } + ] +} diff --git a/tests/topotests/ldp-snmp/r3/show_ldp_igp_sync.ref b/tests/topotests/ldp-snmp/r3/show_ldp_igp_sync.ref new file mode 100644 index 0000000000..73261830c9 --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/show_ldp_igp_sync.ref @@ -0,0 +1,16 @@ +{ + "r3-eth1":{ + "state":"labelExchangeComplete", + "waitTime":10, + "waitTimeRemaining":0, + "timerRunning":false, + "peerLdpId":"1.1.1.1" + }, + "r3-eth2":{ + "state":"labelExchangeComplete", + "waitTime":10, + "waitTimeRemaining":0, + "timerRunning":false, + "peerLdpId":"2.2.2.2" + } +} diff --git a/tests/topotests/ldp-snmp/r3/show_ldp_igp_sync_r1_eth1_shutdown.ref b/tests/topotests/ldp-snmp/r3/show_ldp_igp_sync_r1_eth1_shutdown.ref new file mode 100644 index 0000000000..73261830c9 --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/show_ldp_igp_sync_r1_eth1_shutdown.ref @@ -0,0 +1,16 @@ +{ + "r3-eth1":{ + "state":"labelExchangeComplete", + "waitTime":10, + "waitTimeRemaining":0, + "timerRunning":false, + "peerLdpId":"1.1.1.1" + }, + "r3-eth2":{ + "state":"labelExchangeComplete", + "waitTime":10, + "waitTimeRemaining":0, + "timerRunning":false, + "peerLdpId":"2.2.2.2" + } +} diff --git a/tests/topotests/ldp-snmp/r3/show_ldp_neighbor.ref b/tests/topotests/ldp-snmp/r3/show_ldp_neighbor.ref new file mode 100644 index 0000000000..5c482da697 --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/show_ldp_neighbor.ref @@ -0,0 +1,16 @@ +{ + "neighbors":[ + { + "addressFamily":"ipv4", + "neighborId":"1.1.1.1", + "state":"OPERATIONAL", + "transportAddress":"1.1.1.1" + }, + { + "addressFamily":"ipv4", + "neighborId":"2.2.2.2", + "state":"OPERATIONAL", + "transportAddress":"2.2.2.2" + } + ] +} diff --git a/tests/topotests/ldp-snmp/r3/show_yang_interface_isis_adjacencies.ref b/tests/topotests/ldp-snmp/r3/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 0000000000..0922192361 --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,42 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "r3-eth1", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0001", + "neighbor-extended-circuit-id": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "r3-eth2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1", + "neighbor-sysid": "0000.0000.0002", + "neighbor-extended-circuit-id": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/ldp-snmp/r3/zebra.conf b/tests/topotests/ldp-snmp/r3/zebra.conf new file mode 100644 index 0000000000..b1919bd296 --- /dev/null +++ b/tests/topotests/ldp-snmp/r3/zebra.conf @@ -0,0 +1,32 @@ +log file zebra.log +! +hostname r3 +! +debug zebra rib detailed +debug zebra dplane detailed +debug zebra kernel +debug zebra nht +debug zebra pseudowires +! +interface lo + ip address 3.3.3.3/32 +! +interface r3-eth0 + description to s3 +! +interface r3-eth1 + description to s5 + ip address 10.0.2.3/24 +! +interface r3-eth2 + description to s6 + ip address 10.0.3.3/24 +! +!!interface r3-eth3 +!! description to s4 +!! ip address 10.0.1.3/24 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/ldp-snmp/test_ldp_snmp_topo1.py b/tests/topotests/ldp-snmp/test_ldp_snmp_topo1.py new file mode 100644 index 0000000000..c8760f457a --- /dev/null +++ b/tests/topotests/ldp-snmp/test_ldp_snmp_topo1.py @@ -0,0 +1,373 @@ +#!/usr/bin/env python + +# +# test_ldp_isis_topo1.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2020 by Volta Networks +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_ldp_vpls_topo1.py: + + +---------+ +---------+ + | | | | + | CE1 | | CE2 | + | | | | + +---------+ +---------+ +ce1-eth0 (172.16.1.1/24)| |ce2-eth0 (172.16.1.2/24) + | | + | | + rt1-eth0| |rt2-eth0 + +---------+ 10.0.1.0/24 +---------+ + | |rt1-eth1 | | + | RT1 +----------------+ RT2 | + | 1.1.1.1 | rt2-eth1| 2.2.2.2 | + | | | | + +---------+ +---------+ + rt1-eth2| |rt2-eth2 + | | + | | + 10.0.2.0/24| +---------+ |10.0.3.0/24 + | | | | + | | RT3 | | + +--------+ 3.3.3.3 +-------+ + rt3-eth2| |rt3-eth1 + +---------+ + |rt3-eth0 + | + | + ce3-eth0 (172.16.1.3/24)| + +---------+ + | | + | CE3 | + | | + +---------+ +""" + +import os +import re +import sys +import pytest +import json +from time import sleep +from functools import partial + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger +from lib.snmptest import SnmpTester + +# Required to instantiate the topology builder class. +from mininet.topo import Topo + + +class TemplateTopo(Topo): + "Test topology builder" + + def build(self, *_args, **_opts): + "Build function" + tgen = get_topogen(self) + + # + # Define FRR Routers + # + for router in ["ce1", "ce2", "ce3", "r1", "r2", "r3"]: + tgen.add_router(router) + + # + # Define connections + # + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["ce1"]) + switch.add_link(tgen.gears["r1"]) + + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["ce2"]) + switch.add_link(tgen.gears["r2"]) + + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["ce3"]) + switch.add_link(tgen.gears["r3"]) + + switch = tgen.add_switch("s4") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + switch = tgen.add_switch("s5") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r3"]) + + switch = tgen.add_switch("s6") + switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["r3"]) + + +def setup_module(mod): + "Sets up the pytest environment" + tgen = Topogen(TemplateTopo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + # For all registered routers, load the zebra configuration file + for rname, router in router_list.items(): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + # Don't start isisd and ldpd in the CE nodes + if router.name[0] == "r": + router.load_config( + TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_LDP, os.path.join(CWD, "{}/ldpd.conf".format(rname)), + "-M snmp" + ) + router.load_config( + TopoRouter.RD_SNMP, os.path.join(CWD, "{}/snmpd.conf".format(rname)), + "-Le -Ivacm_conf,usmConf,iquery -V -DAgentX,trap" + ) + + + tgen.start_router() + + +def teardown_module(mod): + "Teardown the pytest environment" + tgen = get_topogen() + + # This function tears down the whole topology. + tgen.stop_topology() + + +def router_compare_json_output(rname, command, reference): + "Compare router JSON output" + + logger.info('Comparing router "%s" "%s" output', rname, command) + + tgen = get_topogen() + filename = "{}/{}/{}".format(CWD, rname, reference) + expected = json.loads(open(filename).read()) + + # Run test function until we get an result. + test_func = partial(topotest.router_json_cmp, tgen.gears[rname], command, expected) + _, diff = topotest.run_and_expect(test_func, None, count=320, wait=0.5) + assertmsg = '"{}" JSON output mismatches the expected result'.format(rname) + assert diff is None, assertmsg + + +def test_isis_convergence(): + logger.info("Test: check ISIS adjacencies") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["r1", "r2", "r3"]: + router_compare_json_output( + rname, + "show yang operational-data /frr-interface:lib isisd", + "show_yang_interface_isis_adjacencies.ref", + ) + + +def test_rib(): + logger.info("Test: verify RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + # TODO: disabling this check to avoid 'snmpd not running' errors + #if tgen.routers_have_failure(): + # pytest.skip(tgen.errors) + + for rname in ["r1", "r2", "r3"]: + router_compare_json_output(rname, "show ip route json", "show_ip_route.ref") + + +def test_ldp_adjacencies(): + logger.info("Test: verify LDP adjacencies") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + # TODO: disabling this check to avoid 'snmpd not running' errors + #if tgen.routers_have_failure(): + # pytest.skip(tgen.errors) + + for rname in ["r1", "r2", "r3"]: + router_compare_json_output( + rname, "show mpls ldp discovery json", "show_ldp_discovery.ref" + ) + + +def test_ldp_neighbors(): + logger.info("Test: verify LDP neighbors") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + #if tgen.routers_have_failure(): + # pytest.skip(tgen.errors) + + for rname in ["r1", "r2", "r3"]: + router_compare_json_output( + rname, "show mpls ldp neighbor json", "show_ldp_neighbor.ref" + ) + + +def test_r1_ldp_lsr_objects(): + "Test mplsLdpLsrObjects objects" + tgen = get_topogen() + + r1 = tgen.net.get("r1") + r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") + + assert r1_snmp.test_oid('mplsLdpLsrId', "01 01 01 01") + assert r1_snmp.test_oid('mplsLdpLsrLoopDetectionCapable', 'none(1)') + + +def test_r1_ldp_entity_table(): + "Test mplsLdpEntityTable" + tgen = get_topogen() + + r1 = tgen.net.get("r1") + r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") + + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityLdpId', ['1.1.1.1:0']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityIndex', ['1']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityProtocolVersion', ['1']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityAdminStatus', ['enable(1)']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityOperStatus', ['enabled(2)']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityTcpPort', ['646']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityUdpDscPort', ['646']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityMaxPduLength', ['4096 octets']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityKeepAliveHoldTimer', ['180 seconds']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityHelloHoldTimer', ['0 seconds']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityInitSessionThreshold', ['0']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityLabelDistMethod', ['downstreamUnsolicited(2)']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityLabelRetentionMode', ['liberal(2)']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityPathVectorLimit', ['0']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityHopCountLimit', ['0']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityTransportAddrKind', ['loopback(2)']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityTargetPeer', ['true(1)']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityTargetPeerAddrType', ['ipv4(1)']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityTargetPeerAddr', ['01 01 01 01']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityLabelType', ['generic(1)']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityDiscontinuityTime', ['(0) 0:00:00.00']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityStorageType', ['nonVolatile(3)']) + assert r1_snmp.test_oid_walk( + 'mplsLdpEntityRowStatus', ['createAndGo(4)']) + + +def test_r1_ldp_peer_table(): + "Test mplsLdpPeerTable" + tgen = get_topogen() + + r1 = tgen.net.get("r1") + r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") + + assert r1_snmp.test_oid_walk( + 'mplsLdpPeerLdpId', ['2.2.2.2:0', '3.3.3.3:0']) + assert r1_snmp.test_oid_walk( + 'mplsLdpPeerLabelDistMethod', + ['downstreamUnsolicited(2)', 'downstreamUnsolicited(2)']) + assert r1_snmp.test_oid_walk( + 'mplsLdpPeerPathVectorLimit', ['0', '0']) + assert r1_snmp.test_oid_walk( + 'mplsLdpPeerTransportAddrType', ['ipv4(1)', 'ipv4(1)']) + assert r1_snmp.test_oid_walk( + 'mplsLdpPeerTransportAddr', ['02 02 02 02', '03 03 03 03']) + + +def test_r1_ldp_session_table(): + "Test mplsLdpSessionTable" + tgen = get_topogen() + + r1 = tgen.net.get("r1") + r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") + + assert r1_snmp.test_oid_walk('mplsLdpSessionState', + ['operational(5)', 'operational(5)']) + assert r1_snmp.test_oid_walk('mplsLdpSessionRole', + ['passive(3)', 'passive(3)']) + assert r1_snmp.test_oid_walk('mplsLdpSessionProtocolVersion', + ['1', '1']) + assert r1_snmp.test_oid_walk('mplsLdpSessionKeepAliveTime', + ['180 seconds', '180 seconds']) + assert r1_snmp.test_oid_walk('mplsLdpSessionMaxPduLength', + ['4096 octets', '4096 octets']) + assert r1_snmp.test_oid_walk('mplsLdpSessionDiscontinuityTime', + ['(0) 0:00:00.00', '(0) 0:00:00.00']) + + +def test_r1_ldp_hello_adjacency_table(): + "Test mplsLdpHelloAdjacencyTable" + tgen = get_topogen() + + r1 = tgen.net.get("r1") + r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") + + assert r1_snmp.test_oid_walk('mplsLdpHelloAdjacencyIndex', + ['1', '2', '1']) + assert r1_snmp.test_oid_walk('mplsLdpHelloAdjacencyHoldTime', + ['15', '45', '15']) + assert r1_snmp.test_oid_walk('mplsLdpHelloAdjacencyType', + ['link(1)', 'targeted(2)', 'link(1)']) + + +# Memory leak test template +# disabling memory leak +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args))