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