summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfdd/bfd.c4
-rw-r--r--bfdd/bfdd_cli.c2
-rw-r--r--bfdd/bfdd_vty.c2
-rw-r--r--bfdd/ptm_adapter.c3
-rw-r--r--bgpd/bgp_io.c47
-rw-r--r--bgpd/bgp_packet.c34
-rw-r--r--bgpd/bgp_packet.h4
-rw-r--r--doc/developer/logging.rst4
-rw-r--r--isisd/isis_adjacency.c17
-rw-r--r--isisd/isis_adjacency.h2
-rw-r--r--isisd/isis_circuit.c74
-rw-r--r--isisd/isis_circuit.h9
-rw-r--r--isisd/isis_dr.c1
-rw-r--r--isisd/isis_dynhn.c35
-rw-r--r--isisd/isis_dynhn.h3
-rw-r--r--isisd/isis_lsp.c8
-rw-r--r--isisd/isis_nb.h89
-rw-r--r--isisd/isis_nb_notifications.c136
-rw-r--r--isisd/isis_pdu.c180
-rw-r--r--isisd/isis_snmp.c3457
-rw-r--r--isisd/isis_spf.c16
-rw-r--r--isisd/isisd.c13
-rw-r--r--isisd/isisd.h18
-rw-r--r--isisd/subdir.am10
-rw-r--r--ldpd/lde.c12
-rw-r--r--ldpd/ldp_snmp.c1087
-rw-r--r--ldpd/ldpd.c29
-rw-r--r--ldpd/ldpd.h9
-rw-r--r--ldpd/ldpe.c20
-rw-r--r--ldpd/ldpe.h5
-rw-r--r--ldpd/neighbor.c31
-rw-r--r--ldpd/subdir.am9
-rw-r--r--lib/agentx.c10
-rw-r--r--lib/northbound.c10
-rw-r--r--lib/smux.h4
-rw-r--r--tests/topotests/isis-snmp/ce3/zebra.conf12
-rw-r--r--tests/topotests/isis-snmp/r1/isisd.conf24
-rw-r--r--tests/topotests/isis-snmp/r1/ldpd.conf26
-rw-r--r--tests/topotests/isis-snmp/r1/show_ip_route.ref143
-rw-r--r--tests/topotests/isis-snmp/r1/show_yang_interface_isis_adjacencies.ref42
-rw-r--r--tests/topotests/isis-snmp/r1/snmpd.conf15
-rw-r--r--tests/topotests/isis-snmp/r1/zebra.conf24
-rw-r--r--tests/topotests/isis-snmp/r2/isisd.conf25
-rw-r--r--tests/topotests/isis-snmp/r2/ldpd.conf25
-rw-r--r--tests/topotests/isis-snmp/r2/show_ip_route.ref143
-rw-r--r--tests/topotests/isis-snmp/r2/show_yang_interface_isis_adjacencies.ref42
-rw-r--r--tests/topotests/isis-snmp/r2/snmpd.conf15
-rw-r--r--tests/topotests/isis-snmp/r2/zebra.conf24
-rw-r--r--tests/topotests/isis-snmp/r3/isisd.conf25
-rw-r--r--tests/topotests/isis-snmp/r3/ldpd.conf25
-rw-r--r--tests/topotests/isis-snmp/r3/show_ip_route.ref143
-rw-r--r--tests/topotests/isis-snmp/r3/show_yang_interface_isis_adjacencies.ref42
-rw-r--r--tests/topotests/isis-snmp/r3/snmpd.conf15
-rw-r--r--tests/topotests/isis-snmp/r3/zebra.conf28
-rw-r--r--tests/topotests/isis-snmp/r4/isisd.conf24
-rw-r--r--tests/topotests/isis-snmp/r4/ldpd.conf25
-rw-r--r--tests/topotests/isis-snmp/r4/show_ip_route.ref143
-rw-r--r--tests/topotests/isis-snmp/r4/show_yang_interface_isis_adjacencies.ref42
-rw-r--r--tests/topotests/isis-snmp/r4/snmpd.conf15
-rw-r--r--tests/topotests/isis-snmp/r4/zebra.conf24
-rw-r--r--tests/topotests/isis-snmp/r5/isisd.conf25
-rw-r--r--tests/topotests/isis-snmp/r5/ldpd.conf25
-rw-r--r--tests/topotests/isis-snmp/r5/ldpdconf25
-rw-r--r--tests/topotests/isis-snmp/r5/show_ip_route.ref143
-rw-r--r--tests/topotests/isis-snmp/r5/show_yang_interface_isis_adjacencies.ref42
-rw-r--r--tests/topotests/isis-snmp/r5/snmpd.conf15
-rw-r--r--tests/topotests/isis-snmp/r5/zebra.conf24
-rw-r--r--tests/topotests/isis-snmp/test_isis_snmp.dot114
-rwxr-xr-xtests/topotests/isis-snmp/test_isis_snmp.py373
-rw-r--r--tests/topotests/ldp-snmp/ce1/zebra.conf12
-rw-r--r--tests/topotests/ldp-snmp/ce2/zebra.conf12
-rw-r--r--tests/topotests/ldp-snmp/ce3/zebra.conf12
-rw-r--r--tests/topotests/ldp-snmp/r1/isisd.conf27
-rw-r--r--tests/topotests/ldp-snmp/r1/ldpd.conf35
-rw-r--r--tests/topotests/ldp-snmp/r1/show_ip_route.ref134
-rw-r--r--tests/topotests/ldp-snmp/r1/show_isis_interface_detail.ref16
-rw-r--r--tests/topotests/ldp-snmp/r1/show_isis_interface_detail_r1_eth1_shutdown.ref16
-rw-r--r--tests/topotests/ldp-snmp/r1/show_isis_interface_detail_r2_eth1_shutdown.ref16
-rw-r--r--tests/topotests/ldp-snmp/r1/show_isis_ldp_sync.ref13
-rw-r--r--tests/topotests/ldp-snmp/r1/show_isis_ldp_sync_r1_eth1_shutdown.ref11
-rw-r--r--tests/topotests/ldp-snmp/r1/show_isis_ldp_sync_r2_eth1_shutdown.ref13
-rw-r--r--tests/topotests/ldp-snmp/r1/show_l2vpn_binding.ref16
-rw-r--r--tests/topotests/ldp-snmp/r1/show_l2vpn_vc.ref8
-rw-r--r--tests/topotests/ldp-snmp/r1/show_ldp_binding.ref44
-rw-r--r--tests/topotests/ldp-snmp/r1/show_ldp_discovery.ref25
-rw-r--r--tests/topotests/ldp-snmp/r1/show_ldp_igp_sync.ref16
-rw-r--r--tests/topotests/ldp-snmp/r1/show_ldp_igp_sync_r1_eth1_shutdown.ref16
-rw-r--r--tests/topotests/ldp-snmp/r1/show_ldp_neighbor.ref16
-rw-r--r--tests/topotests/ldp-snmp/r1/show_yang_interface_isis_adjacencies.ref42
-rw-r--r--tests/topotests/ldp-snmp/r1/snmpd.conf15
-rw-r--r--tests/topotests/ldp-snmp/r1/zebra.conf29
-rw-r--r--tests/topotests/ldp-snmp/r2/isisd.conf28
-rw-r--r--tests/topotests/ldp-snmp/r2/ldpd.conf35
-rw-r--r--tests/topotests/ldp-snmp/r2/ospfd.conf19
-rw-r--r--tests/topotests/ldp-snmp/r2/show_ip_route.ref134
-rw-r--r--tests/topotests/ldp-snmp/r2/show_isis_interface_detail.ref16
-rw-r--r--tests/topotests/ldp-snmp/r2/show_isis_interface_detail_r1_eth1_shutdown.ref16
-rw-r--r--tests/topotests/ldp-snmp/r2/show_isis_interface_detail_r2_eth1_shutdown.ref16
-rw-r--r--tests/topotests/ldp-snmp/r2/show_isis_ldp_sync.ref13
-rw-r--r--tests/topotests/ldp-snmp/r2/show_isis_ldp_sync_r1_eth1_shutdown.ref13
-rw-r--r--tests/topotests/ldp-snmp/r2/show_isis_ldp_sync_r2_eth1_shutdown.ref11
-rw-r--r--tests/topotests/ldp-snmp/r2/show_l2vpn_binding.ref16
-rw-r--r--tests/topotests/ldp-snmp/r2/show_l2vpn_vc.ref8
-rw-r--r--tests/topotests/ldp-snmp/r2/show_ldp_binding.ref44
-rw-r--r--tests/topotests/ldp-snmp/r2/show_ldp_discovery.ref25
-rw-r--r--tests/topotests/ldp-snmp/r2/show_ldp_igp_sync.ref16
-rw-r--r--tests/topotests/ldp-snmp/r2/show_ldp_igp_sync_r1_eth1_shutdown.ref16
-rw-r--r--tests/topotests/ldp-snmp/r2/show_ldp_igp_sync_r2_eth1_shutdown.ref16
-rw-r--r--tests/topotests/ldp-snmp/r2/show_ldp_neighbor.ref16
-rw-r--r--tests/topotests/ldp-snmp/r2/show_yang_interface_isis_adjacencies.ref42
-rw-r--r--tests/topotests/ldp-snmp/r2/snmpd.conf15
-rw-r--r--tests/topotests/ldp-snmp/r2/zebra.conf28
-rw-r--r--tests/topotests/ldp-snmp/r3/isisd.conf29
-rw-r--r--tests/topotests/ldp-snmp/r3/ldpd.conf27
-rw-r--r--tests/topotests/ldp-snmp/r3/show_ip_route.ref134
-rw-r--r--tests/topotests/ldp-snmp/r3/show_isis_interface_detail.ref16
-rw-r--r--tests/topotests/ldp-snmp/r3/show_isis_interface_detail_r1_eth1_shutdown.ref16
-rw-r--r--tests/topotests/ldp-snmp/r3/show_isis_interface_detail_r2_eth1_shutdown.ref16
-rw-r--r--tests/topotests/ldp-snmp/r3/show_isis_ldp_sync.ref13
-rw-r--r--tests/topotests/ldp-snmp/r3/show_isis_ldp_sync_r1_eth1_shutdown.ref13
-rw-r--r--tests/topotests/ldp-snmp/r3/show_isis_ldp_sync_r2_eth1_shutdown.ref13
-rw-r--r--tests/topotests/ldp-snmp/r3/show_l2vpn_binding.ref2
-rw-r--r--tests/topotests/ldp-snmp/r3/show_l2vpn_vc.ref2
-rw-r--r--tests/topotests/ldp-snmp/r3/show_ldp_binding.ref44
-rw-r--r--tests/topotests/ldp-snmp/r3/show_ldp_discovery.ref18
-rw-r--r--tests/topotests/ldp-snmp/r3/show_ldp_igp_sync.ref16
-rw-r--r--tests/topotests/ldp-snmp/r3/show_ldp_igp_sync_r1_eth1_shutdown.ref16
-rw-r--r--tests/topotests/ldp-snmp/r3/show_ldp_neighbor.ref16
-rw-r--r--tests/topotests/ldp-snmp/r3/show_yang_interface_isis_adjacencies.ref42
-rw-r--r--tests/topotests/ldp-snmp/r3/zebra.conf32
-rw-r--r--tests/topotests/ldp-snmp/test_ldp_snmp_topo1.py373
-rwxr-xr-xvtysh/extract.pl.in2
-rw-r--r--yang/frr-bfdd.yang2
133 files changed, 9068 insertions, 152 deletions
diff --git a/bfdd/bfd.c b/bfdd/bfd.c
index 499e54603f..3cbb3691ec 100644
--- a/bfdd/bfd.c
+++ b/bfdd/bfd.c
@@ -85,7 +85,7 @@ struct bfd_profile *bfd_profile_lookup(const char *name)
static void bfd_profile_set_default(struct bfd_profile *bp)
{
- bp->admin_shutdown = true;
+ bp->admin_shutdown = false;
bp->detection_multiplier = BFD_DEFDETECTMULT;
bp->echo_mode = false;
bp->passive = false;
@@ -206,7 +206,7 @@ void bfd_session_apply(struct bfd_session *bs)
bfd_set_passive_mode(bs, bs->peer_profile.passive);
/* Toggle 'no shutdown' if default value. */
- if (bs->peer_profile.admin_shutdown)
+ if (bs->peer_profile.admin_shutdown == false)
bfd_set_shutdown(bs, bp->admin_shutdown);
else
bfd_set_shutdown(bs, bs->peer_profile.admin_shutdown);
diff --git a/bfdd/bfdd_cli.c b/bfdd/bfdd_cli.c
index 5072c76aac..206f6c7d0c 100644
--- a/bfdd/bfdd_cli.c
+++ b/bfdd/bfdd_cli.c
@@ -274,7 +274,7 @@ void bfd_cli_show_shutdown(struct vty *vty, struct lyd_node *dnode,
bool show_defaults)
{
if (show_defaults)
- vty_out(vty, " shutdown\n");
+ vty_out(vty, " no shutdown\n");
else
vty_out(vty, " %sshutdown\n",
yang_dnode_get_bool(dnode, NULL) ? "" : "no ");
diff --git a/bfdd/bfdd_vty.c b/bfdd/bfdd_vty.c
index 53e23cf6c2..cb140f7b18 100644
--- a/bfdd/bfdd_vty.c
+++ b/bfdd/bfdd_vty.c
@@ -840,7 +840,7 @@ static int bfd_configure_peer(struct bfd_peer_cfg *bpc, bool mhop,
memset(bpc, 0, sizeof(*bpc));
/* Defaults */
- bpc->bpc_shutdown = true;
+ bpc->bpc_shutdown = false;
bpc->bpc_detectmultiplier = BPC_DEF_DETECTMULTIPLIER;
bpc->bpc_recvinterval = BPC_DEF_RECEIVEINTERVAL;
bpc->bpc_txinterval = BPC_DEF_TRANSMITINTERVAL;
diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c
index 0c70600f20..4135e5fb49 100644
--- a/bfdd/ptm_adapter.c
+++ b/bfdd/ptm_adapter.c
@@ -492,9 +492,6 @@ static void bfdd_dest_register(struct stream *msg, vrf_id_t vrf_id)
"ptm-add-dest: failed to create BFD session");
return;
}
-
- /* Protocol created peers are 'no shutdown' by default. */
- bs->peer_profile.admin_shutdown = false;
} else {
/*
* BFD session was already created, we are just updating the
diff --git a/bgpd/bgp_io.c b/bgpd/bgp_io.c
index 9a178395b8..7aa489e932 100644
--- a/bgpd/bgp_io.c
+++ b/bgpd/bgp_io.c
@@ -45,7 +45,7 @@
/* forward declarations */
static uint16_t bgp_write(struct peer *);
-static uint16_t bgp_read(struct peer *);
+static uint16_t bgp_read(struct peer *peer, int *code_p);
static int bgp_process_writes(struct thread *);
static int bgp_process_reads(struct thread *);
static bool validate_header(struct peer *);
@@ -181,6 +181,7 @@ static int bgp_process_reads(struct thread *thread)
bool fatal = false; // whether fatal error occurred
bool added_pkt = false; // whether we pushed onto ->ibuf
/* clang-format on */
+ int code;
peer = THREAD_ARG(thread);
@@ -190,7 +191,7 @@ static int bgp_process_reads(struct thread *thread)
struct frr_pthread *fpt = bgp_pth_io;
frr_with_mutex(&peer->io_mtx) {
- status = bgp_read(peer);
+ status = bgp_read(peer, &code);
}
/* error checking phase */
@@ -203,6 +204,12 @@ static int bgp_process_reads(struct thread *thread)
/* problem; tear down session */
more = false;
fatal = true;
+
+ /* Handle the error in the main pthread, include the
+ * specific state change from 'bgp_read'.
+ */
+ thread_add_event(bm->master, bgp_packet_process_error,
+ peer, code, NULL);
}
while (more) {
@@ -236,6 +243,7 @@ static int bgp_process_reads(struct thread *thread)
*/
if (ringbuf_remain(ibw) >= pktsize) {
struct stream *pkt = stream_new(pktsize);
+
assert(STREAM_WRITEABLE(pkt) == pktsize);
assert(ringbuf_get(ibw, pkt->data, pktsize) == pktsize);
stream_set_endp(pkt, pktsize);
@@ -449,7 +457,7 @@ done : {
*
* @return status flag (see top-of-file)
*/
-static uint16_t bgp_read(struct peer *peer)
+static uint16_t bgp_read(struct peer *peer, int *code_p)
{
ssize_t nbytes; // how many bytes we actually read
uint16_t status = 0;
@@ -459,43 +467,28 @@ static uint16_t bgp_read(struct peer *peer)
/* EAGAIN or EWOULDBLOCK; come back later */
if (nbytes < 0 && ERRNO_IO_RETRY(errno)) {
SET_FLAG(status, BGP_IO_TRANS_ERR);
- /* Fatal error; tear down session */
} else if (nbytes < 0) {
+ /* Fatal error; tear down session */
flog_err(EC_BGP_UPDATE_RCV,
"%s [Error] bgp_read_packet error: %s", peer->host,
safe_strerror(errno));
- if (peer->status == Established) {
- if ((CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART)
- || CHECK_FLAG(peer->flags,
- PEER_FLAG_GRACEFUL_RESTART_HELPER))
- && CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE)) {
- peer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION;
- SET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT);
- } else
- peer->last_reset = PEER_DOWN_CLOSE_SESSION;
- }
+ /* Handle the error in the main pthread. */
+ if (code_p)
+ *code_p = TCP_fatal_error;
- BGP_EVENT_ADD(peer, TCP_fatal_error);
SET_FLAG(status, BGP_IO_FATAL_ERR);
- /* Received EOF / TCP session closed */
+
} else if (nbytes == 0) {
+ /* Received EOF / TCP session closed */
if (bgp_debug_neighbor_events(peer))
zlog_debug("%s [Event] BGP connection closed fd %d",
peer->host, peer->fd);
- if (peer->status == Established) {
- if ((CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART)
- || CHECK_FLAG(peer->flags,
- PEER_FLAG_GRACEFUL_RESTART_HELPER))
- && CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE)) {
- peer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION;
- SET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT);
- } else
- peer->last_reset = PEER_DOWN_CLOSE_SESSION;
- }
+ /* Handle the error in the main pthread. */
+ if (code_p)
+ *code_p = TCP_connection_closed;
- BGP_EVENT_ADD(peer, TCP_connection_closed);
SET_FLAG(status, BGP_IO_FATAL_ERR);
}
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index ff2cc26d42..f04b89594e 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -2699,3 +2699,37 @@ void bgp_send_delayed_eor(struct bgp *bgp)
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer))
bgp_write_proceed_actions(peer);
}
+
+/*
+ * Task callback to handle socket error encountered in the io pthread. We avoid
+ * having the io pthread try to enqueue fsm events or mess with the peer
+ * struct.
+ */
+int bgp_packet_process_error(struct thread *thread)
+{
+ struct peer *peer;
+ int code;
+
+ peer = THREAD_ARG(thread);
+ code = THREAD_VAL(thread);
+
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug("%s [Event] BGP error %d on fd %d",
+ peer->host, peer->fd, code);
+
+ /* Closed connection or error on the socket */
+ if (peer->status == Established) {
+ if ((CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART)
+ || CHECK_FLAG(peer->flags,
+ PEER_FLAG_GRACEFUL_RESTART_HELPER))
+ && CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE)) {
+ peer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION;
+ SET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT);
+ } else
+ peer->last_reset = PEER_DOWN_CLOSE_SESSION;
+ }
+
+ bgp_event_update(peer, code);
+
+ return 0;
+}
diff --git a/bgpd/bgp_packet.h b/bgpd/bgp_packet.h
index 525859a2da..d32f091d0c 100644
--- a/bgpd/bgp_packet.h
+++ b/bgpd/bgp_packet.h
@@ -83,4 +83,8 @@ extern int bgp_generate_updgrp_packets(struct thread *);
extern int bgp_process_packet(struct thread *);
extern void bgp_send_delayed_eor(struct bgp *bgp);
+
+/* Task callback to handle socket error encountered in the io pthread */
+int bgp_packet_process_error(struct thread *thread);
+
#endif /* _QUAGGA_BGP_PACKET_H */
diff --git a/doc/developer/logging.rst b/doc/developer/logging.rst
index cf3aa8d17f..a35e60619c 100644
--- a/doc/developer/logging.rst
+++ b/doc/developer/logging.rst
@@ -71,6 +71,10 @@ Extensions
+-----------+--------------------------+----------------------------------------------+
| ``%pI6`` | ``struct in6_addr *`` | ``fe80::1234`` |
+-----------+--------------------------+----------------------------------------------+
+| ``%pIA`` | ``struct ipaddr *`` | ``1.2.3.4`` |
+| | | |
+| | | ``fe80::1234`` |
++-----------+--------------------------+----------------------------------------------+
| ``%pFX`` | ``struct prefix *`` | ``fe80::1234/64`` |
+-----------+--------------------------+----------------------------------------------+
| ``%pSG4`` | ``struct prefix_sg *`` | ``(*,1.2.3.4)`` |
diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c
index 71d4758163..3c3a68764e 100644
--- a/isisd/isis_adjacency.c
+++ b/isisd/isis_adjacency.c
@@ -49,13 +49,21 @@
#include "isisd/fabricd.h"
#include "isisd/isis_nb.h"
-static struct isis_adjacency *adj_alloc(const uint8_t *id)
+static struct isis_adjacency *adj_alloc(struct isis_circuit *circuit,
+ const uint8_t *id)
{
struct isis_adjacency *adj;
adj = XCALLOC(MTYPE_ISIS_ADJACENCY, sizeof(struct isis_adjacency));
memcpy(adj->sysid, id, ISIS_SYS_ID_LEN);
+ adj->snmp_idx = ++circuit->snmp_adj_idx_gen;
+
+ if (circuit->snmp_adj_list == NULL)
+ circuit->snmp_adj_list = list_new();
+
+ adj->snmp_list_node = listnode_add(circuit->snmp_adj_list, adj);
+
return adj;
}
@@ -65,7 +73,7 @@ struct isis_adjacency *isis_new_adj(const uint8_t *id, const uint8_t *snpa,
struct isis_adjacency *adj;
int i;
- adj = adj_alloc(id); /* P2P kludge */
+ adj = adj_alloc(circuit, id); /* P2P kludge */
if (snpa) {
memcpy(adj->snpa, snpa, ETH_ALEN);
@@ -146,6 +154,8 @@ void isis_delete_adj(void *arg)
if (!adj)
return;
+ /* Remove self from snmp list without walking the list*/
+ list_delete_node(adj->circuit->snmp_adj_list, adj->snmp_list_node);
thread_cancel(&adj->t_expire);
if (adj->adj_state != ISIS_ADJ_DOWN)
@@ -292,7 +302,6 @@ void isis_adj_state_change(struct isis_adjacency **padj,
if (circuit->area->log_adj_changes)
isis_log_adj_change(adj, old_state, new_state, reason);
- circuit->adj_state_changes++;
#ifndef FABRICD
/* send northbound notification */
isis_notif_adj_state_change(adj, new_state, reason);
@@ -303,12 +312,14 @@ void isis_adj_state_change(struct isis_adjacency **padj,
if ((adj->level & level) == 0)
continue;
if (new_state == ISIS_ADJ_UP) {
+ circuit->adj_state_changes++;
circuit->upadjcount[level - 1]++;
/* update counter & timers for debugging
* purposes */
adj->last_flap = time(NULL);
adj->flaps++;
} else if (old_state == ISIS_ADJ_UP) {
+ circuit->adj_state_changes++;
listnode_delete(circuit->u.bc.adjdb[level - 1],
adj);
diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h
index 2780d826f5..3afb7209f3 100644
--- a/isisd/isis_adjacency.h
+++ b/isisd/isis_adjacency.h
@@ -105,6 +105,8 @@ struct isis_adjacency {
unsigned int mt_count; /* Number of entries in mt_set */
struct bfd_session *bfd_session;
struct list *adj_sids; /* Segment Routing Adj-SIDs. */
+ uint32_t snmp_idx;
+ struct listnode *snmp_list_node;
};
struct isis_threeway_adj;
diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c
index 4aac3f8880..62822cbf89 100644
--- a/isisd/isis_circuit.c
+++ b/isisd/isis_circuit.c
@@ -71,6 +71,48 @@ DEFINE_HOOK(isis_if_new_hook, (struct interface *ifp), (ifp))
int isis_if_new_hook(struct interface *);
int isis_if_delete_hook(struct interface *);
+static int isis_circuit_smmp_id_gen(struct isis_circuit *circuit)
+{
+ struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+ struct isis *isis = NULL;
+ uint32_t id;
+ uint32_t i;
+
+ isis = isis_lookup_by_vrfid(vrf->vrf_id);
+ if (isis == NULL)
+ return 0;
+
+ id = isis->snmp_circuit_id_last;
+ id++;
+
+ /* find next unused entry */
+ for (i = 0; i < SNMP_CIRCUITS_MAX; i++) {
+ if (id >= SNMP_CIRCUITS_MAX) {
+ id = 0;
+ continue;
+ }
+
+ if (id == 0)
+ continue;
+
+ if (isis->snmp_circuits[id] == NULL)
+ break;
+
+ id++;
+ }
+
+ if (i == SNMP_CIRCUITS_MAX) {
+ zlog_warn("Could not allocate a smmp-circuit-id");
+ return 0;
+ }
+
+ isis->snmp_circuits[id] = circuit;
+ isis->snmp_circuit_id_last = id;
+ circuit->snmp_id = id;
+
+ return 1;
+}
+
struct isis_circuit *isis_circuit_new(struct isis *isis)
{
struct isis_circuit *circuit;
@@ -80,6 +122,12 @@ struct isis_circuit *isis_circuit_new(struct isis *isis)
circuit->isis = isis;
/*
+ * Note: if snmp-id generation failed circuit will fail
+ * up operation
+ */
+ isis_circuit_smmp_id_gen(circuit);
+
+ /*
* Default values
*/
#ifndef FABRICD
@@ -150,11 +198,18 @@ struct isis_circuit *isis_circuit_new(struct isis *isis)
void isis_circuit_del(struct isis_circuit *circuit)
{
+ struct isis *isis = NULL;
+
if (!circuit)
return;
QOBJ_UNREG(circuit);
+ if (circuit->interface) {
+ isis = isis_lookup_by_vrfid(circuit->interface->vrf_id);
+ isis->snmp_circuits[circuit->snmp_id] = NULL;
+ }
+
isis_circuit_if_unbind(circuit, circuit->interface);
circuit_mt_finish(circuit);
@@ -609,6 +664,7 @@ int isis_circuit_up(struct isis_circuit *circuit)
return ISIS_OK;
if (circuit->is_passive) {
+ circuit->last_uptime = time(NULL);
/* make sure the union fields are initialized, else we
* could end with garbage values from a previous circuit
* type, which would then cause a segfault when building
@@ -623,6 +679,13 @@ int isis_circuit_up(struct isis_circuit *circuit)
return ISIS_OK;
}
+ if (circuit->snmp_id == 0) {
+ /* We cannot bring circuit up if does not have snmp-id */
+ flog_err(EC_ISIS_CONFIG,
+ "No snnmp-id: there are too many circuits:");
+ return ISIS_ERROR;
+ }
+
if (circuit->area->lsp_mtu > isis_circuit_pdu_size(circuit)) {
flog_err(
EC_ISIS_CONFIG,
@@ -722,6 +785,8 @@ int isis_circuit_up(struct isis_circuit *circuit)
circuit->tx_queue = isis_tx_queue_new(circuit, send_lsp);
+ circuit->last_uptime = time(NULL);
+
#ifndef FABRICD
/* send northbound notification */
isis_notif_if_state_change(circuit, false);
@@ -828,6 +893,15 @@ void isis_circuit_down(struct isis_circuit *circuit)
thread_cancel(&circuit->u.p2p.t_send_p2p_hello);
}
+ /*
+ * All adjacencies have to be gone, delete snmp list
+ * and reset snmpd idx generator
+ */
+ if (circuit->snmp_adj_list != NULL)
+ list_delete(&circuit->snmp_adj_list);
+
+ circuit->snmp_adj_idx_gen = 0;
+
/* Cancel all active threads */
thread_cancel(&circuit->t_send_csnp[0]);
thread_cancel(&circuit->t_send_csnp[1]);
diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h
index 3387232da2..15d58bd736 100644
--- a/isisd/isis_circuit.h
+++ b/isisd/isis_circuit.h
@@ -79,6 +79,7 @@ struct isis_circuit_arg {
struct isis_circuit {
int state;
uint8_t circuit_id; /* l1/l2 bcast CircuitID */
+ time_t last_uptime;
struct isis *isis;
struct isis_area *area; /* back pointer to the area */
struct interface *interface; /* interface info from z */
@@ -115,6 +116,8 @@ struct isis_circuit {
int pad_hellos; /* add padding to Hello PDUs ? */
char ext_domain; /* externalDomain (boolean) */
int lsp_regenerate_pending[ISIS_LEVELS];
+ uint64_t lsp_error_counter;
+
/*
* Configurables
*/
@@ -165,6 +168,12 @@ struct isis_circuit {
uint32_t auth_type_failures; /*authentication-type-fails */
uint32_t auth_failures; /* authentication-fails */
+ uint32_t snmp_id; /* Circuit id in snmp */
+
+ uint32_t snmp_adj_idx_gen; /* Create unique id for adjacency on creation
+ */
+ struct list *snmp_adj_list; /* List in id order */
+
QOBJ_FIELDS
};
DECLARE_QOBJ_TYPE(isis_circuit)
diff --git a/isisd/isis_dr.c b/isisd/isis_dr.c
index f6175fe9a4..e09e23aaeb 100644
--- a/isisd/isis_dr.c
+++ b/isisd/isis_dr.c
@@ -97,6 +97,7 @@ static int isis_check_dr_change(struct isis_adjacency *adj, int level)
/* was there a DIS state transition ? */
{
adj->dischanges[level - 1]++;
+ adj->circuit->desig_changes[level - 1]++;
/* ok rotate the history list through */
for (i = DIS_RECORDS - 1; i > 0; i--) {
adj->dis_record[(i * ISIS_LEVELS) + level - 1].dis =
diff --git a/isisd/isis_dynhn.c b/isisd/isis_dynhn.c
index 244f388c26..d2c5d93e25 100644
--- a/isisd/isis_dynhn.c
+++ b/isisd/isis_dynhn.c
@@ -166,3 +166,38 @@ void dynhn_print_all(struct vty *vty, struct isis *isis)
cmd_hostname_get());
return;
}
+
+struct isis_dynhn *dynhn_snmp_next(const uint8_t *id, int level)
+{
+ struct listnode *node = NULL;
+ struct isis_dynhn *dyn = NULL;
+ struct isis_dynhn *found_dyn = NULL;
+ int res;
+
+ for (ALL_LIST_ELEMENTS_RO(dyn_cache, node, dyn)) {
+ res = memcmp(dyn->id, id, ISIS_SYS_ID_LEN);
+
+ if (res < 0)
+ continue;
+
+ if (res == 0 && dyn->level <= level)
+ continue;
+
+ if (res == 0) {
+ /*
+ * This is the best match, we can stop
+ * searching
+ */
+
+ found_dyn = dyn;
+ break;
+ }
+
+ if (found_dyn == NULL
+ || memcmp(dyn->id, found_dyn->id, ISIS_SYS_ID_LEN) < 0) {
+ found_dyn = dyn;
+ }
+ }
+
+ return found_dyn;
+}
diff --git a/isisd/isis_dynhn.h b/isisd/isis_dynhn.h
index 973fde8307..8d25582e49 100644
--- a/isisd/isis_dynhn.h
+++ b/isisd/isis_dynhn.h
@@ -38,4 +38,7 @@ struct isis_dynhn *dynhn_find_by_id(const uint8_t *id);
struct isis_dynhn *dynhn_find_by_name(const char *hostname);
void dynhn_print_all(struct vty *vty, struct isis *isis);
+/* Snmp support */
+struct isis_dynhn *dynhn_snmp_next(const uint8_t *id, int level);
+
#endif /* _ZEBRA_ISIS_DYNHN_H */
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
index a17d9a6ae2..06a5a69e3f 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -324,8 +324,8 @@ void lsp_inc_seqno(struct isis_lsp *lsp, uint32_t seqno)
/* check for overflow */
if (newseq < lsp->hdr.seqno) {
/* send northbound notification */
- isis_notif_lsp_exceed_max(lsp->area,
- rawlspid_print(lsp->hdr.lsp_id));
+ lsp->area->lsp_exceeded_max_counter++;
+ isis_notif_lsp_exceed_max(lsp->area, lsp->hdr.lsp_id);
}
#endif /* ifndef FABRICD */
@@ -1357,8 +1357,8 @@ int lsp_generate(struct isis_area *area, int level)
#ifndef FABRICD
/* send northbound notification */
- isis_notif_lsp_gen(area, rawlspid_print(newlsp->hdr.lsp_id),
- newlsp->hdr.seqno, newlsp->last_generated);
+ isis_notif_lsp_gen(area, newlsp->hdr.lsp_id, newlsp->hdr.seqno,
+ newlsp->last_generated);
#endif /* ifndef FABRICD */
return ISIS_OK;
diff --git a/isisd/isis_nb.h b/isisd/isis_nb.h
index dfa77fbaca..a6841b9fd4 100644
--- a/isisd/isis_nb.h
+++ b/isisd/isis_nb.h
@@ -549,40 +549,97 @@ void cli_show_isis_mpls_if_ldp_sync_holddown(struct vty *vty,
/* Notifications. */
void isis_notif_db_overload(const struct isis_area *area, bool overload);
void isis_notif_lsp_too_large(const struct isis_circuit *circuit,
- uint32_t pdu_size, const char *lsp_id);
+ uint32_t pdu_size, const uint8_t *lsp_id);
void isis_notif_if_state_change(const struct isis_circuit *circuit, bool down);
void isis_notif_corrupted_lsp(const struct isis_area *area,
- const char *lsp_id); /* currently unused */
+ const uint8_t *lsp_id); /* currently unused */
void isis_notif_lsp_exceed_max(const struct isis_area *area,
- const char *lsp_id);
+ const uint8_t *lsp_id);
void isis_notif_max_area_addr_mismatch(const struct isis_circuit *circuit,
uint8_t max_area_addrs,
- const char *raw_pdu);
+ const char *raw_pdu, size_t raw_pdu_len);
void isis_notif_authentication_type_failure(const struct isis_circuit *circuit,
- const char *raw_pdu);
+ const char *raw_pdu,
+ size_t raw_pdu_len);
void isis_notif_authentication_failure(const struct isis_circuit *circuit,
- const char *raw_pdu);
+ const char *raw_pdu, size_t raw_pdu_len);
void isis_notif_adj_state_change(const struct isis_adjacency *adj,
int new_state, const char *reason);
void isis_notif_reject_adjacency(const struct isis_circuit *circuit,
- const char *reason, const char *raw_pdu);
+ const char *reason, const char *raw_pdu,
+ size_t raw_pdu_len);
void isis_notif_area_mismatch(const struct isis_circuit *circuit,
- const char *raw_pdu);
+ const char *raw_pdu, size_t raw_pdu_len);
void isis_notif_lsp_received(const struct isis_circuit *circuit,
- const char *lsp_id, uint32_t seqno,
+ const uint8_t *lsp_id, uint32_t seqno,
uint32_t timestamp, const char *sys_id);
-void isis_notif_lsp_gen(const struct isis_area *area, const char *lsp_id,
+void isis_notif_lsp_gen(const struct isis_area *area, const uint8_t *lsp_id,
uint32_t seqno, uint32_t timestamp);
void isis_notif_id_len_mismatch(const struct isis_circuit *circuit,
- uint8_t rcv_id_len, const char *raw_pdu);
+ uint8_t rcv_id_len, const char *raw_pdu,
+ size_t raw_pdu_len);
void isis_notif_version_skew(const struct isis_circuit *circuit,
- uint8_t version, const char *raw_pdu);
+ uint8_t version, const char *raw_pdu,
+ size_t raw_pdu_len);
void isis_notif_lsp_error(const struct isis_circuit *circuit,
- const char *lsp_id, const char *raw_pdu,
- uint32_t offset, uint8_t tlv_type);
+ const uint8_t *lsp_id, const char *raw_pdu,
+ size_t raw_pdu_len, uint32_t offset,
+ uint8_t tlv_type);
void isis_notif_seqno_skipped(const struct isis_circuit *circuit,
- const char *lsp_id);
+ const uint8_t *lsp_id);
void isis_notif_own_lsp_purge(const struct isis_circuit *circuit,
- const char *lsp_id);
+ const uint8_t *lsp_id);
+
+/* We also declare hook for every notification */
+
+DECLARE_HOOK(isis_hook_db_overload, (const struct isis_area *area), (area));
+DECLARE_HOOK(isis_hook_lsp_too_large,
+ (const struct isis_circuit *circuit, uint32_t pdu_size,
+ const uint8_t *lsp_id),
+ (circuit, pdu_size, lsp_id));
+/* Note: no isis_hook_corrupted_lsp - because this notificaiton is not used */
+DECLARE_HOOK(isis_hook_lsp_exceed_max,
+ (const struct isis_area *area, const uint8_t *lsp_id),
+ (area, lsp_id));
+DECLARE_HOOK(isis_hook_max_area_addr_mismatch,
+ (const struct isis_circuit *circuit, uint8_t max_addrs,
+ const char *raw_pdu, size_t raw_pdu_len),
+ (circuit, max_addrs, raw_pdu, raw_pdu_len));
+DECLARE_HOOK(isis_hook_authentication_type_failure,
+ (const struct isis_circuit *circuit, const char *raw_pdu,
+ size_t raw_pdu_len),
+ (circuit, raw_pdu, raw_pdu_len));
+DECLARE_HOOK(isis_hook_authentication_failure,
+ (const struct isis_circuit *circuit, const char *raw_pdu,
+ size_t raw_pdu_len),
+ (circuit, raw_pdu, raw_pdu_len));
+DECLARE_HOOK(isis_hook_adj_state_change, (const struct isis_adjacency *adj),
+ (adj));
+DECLARE_HOOK(isis_hook_reject_adjacency,
+ (const struct isis_circuit *circuit, const char *pdu,
+ size_t pdu_len),
+ (circuit, pdu, pdu_len));
+DECLARE_HOOK(isis_hook_area_mismatch,
+ (const struct isis_circuit *circuit, const char *raw_pdu,
+ size_t raw_pdu_len),
+ (circuit));
+DECLARE_HOOK(isis_hook_id_len_mismatch,
+ (const struct isis_circuit *circuit, uint8_t rcv_id_len,
+ const char *raw_pdu, size_t raw_pdu_len),
+ (circuit, rcv_id_len, raw_pdu, raw_pdu_len));
+DECLARE_HOOK(isis_hook_version_skew,
+ (const struct isis_circuit *circuit, uint8_t version,
+ const char *raw_pdu, size_t raw_pdu_len),
+ (circuit));
+DECLARE_HOOK(isis_hook_lsp_error,
+ (const struct isis_circuit *circuit, const uint8_t *lsp_id,
+ const char *raw_pdu, size_t raw_pdu_len),
+ (circuit));
+DECLARE_HOOK(isis_hook_seqno_skipped,
+ (const struct isis_circuit *circuit, const uint8_t *lsp_id),
+ (circuit, lsp_id));
+DECLARE_HOOK(isis_hook_own_lsp_purge,
+ (const struct isis_circuit *circuit, const uint8_t *lsp_id),
+ (circuit, lsp_id));
#endif /* ISISD_ISIS_NB_H_ */
diff --git a/isisd/isis_nb_notifications.c b/isisd/isis_nb_notifications.c
index ea33ec10ec..755378a9b7 100644
--- a/isisd/isis_nb_notifications.c
+++ b/isisd/isis_nb_notifications.c
@@ -28,6 +28,56 @@
#include "isisd/isis_dynhn.h"
#include "isisd/isis_misc.h"
+DEFINE_HOOK(isis_hook_lsp_too_large,
+ (const struct isis_circuit *circuit, uint32_t pdu_size,
+ const uint8_t *lsp_id),
+ (circuit, pdu_size, lsp_id));
+DEFINE_HOOK(isis_hook_corrupted_lsp, (const struct isis_area *area), (area));
+DEFINE_HOOK(isis_hook_lsp_exceed_max,
+ (const struct isis_area *area, const uint8_t *lsp_id),
+ (area, lsp_id));
+DEFINE_HOOK(isis_hook_max_area_addr_mismatch,
+ (const struct isis_circuit *circuit, uint8_t max_addrs,
+ const char *raw_pdu, size_t raw_pdu_len),
+ (circuit, max_addrs, raw_pdu, raw_pdu_len));
+DEFINE_HOOK(isis_hook_authentication_type_failure,
+ (const struct isis_circuit *circuit, const char *raw_pdu,
+ size_t raw_pdu_len),
+ (circuit, raw_pdu, raw_pdu_len));
+DEFINE_HOOK(isis_hook_authentication_failure,
+ (const struct isis_circuit *circuit, const char *raw_pdu,
+ size_t raw_pdu_len),
+ (circuit, raw_pdu, raw_pdu_len));
+DEFINE_HOOK(isis_hook_adj_state_change, (const struct isis_adjacency *adj),
+ (adj));
+DEFINE_HOOK(isis_hook_reject_adjacency,
+ (const struct isis_circuit *circuit, const char *raw_pdu,
+ size_t raw_pdu_len),
+ (circuit, raw_pdu, raw_pdu_len));
+DEFINE_HOOK(isis_hook_area_mismatch,
+ (const struct isis_circuit *circuit, const char *raw_pdu,
+ size_t raw_pdu_len),
+ (circuit, raw_pdu, raw_pdu_len));
+DEFINE_HOOK(isis_hook_id_len_mismatch,
+ (const struct isis_circuit *circuit, uint8_t rcv_id_len,
+ const char *raw_pdu, size_t raw_pdu_len),
+ (circuit, rcv_id_len, raw_pdu, raw_pdu_len));
+DEFINE_HOOK(isis_hook_version_skew,
+ (const struct isis_circuit *circuit, uint8_t version,
+ const char *raw_pdu, size_t raw_pdu_len),
+ (circuit, version, raw_pdu, raw_pdu_len));
+DEFINE_HOOK(isis_hook_lsp_error,
+ (const struct isis_circuit *circuit, const uint8_t *lsp_id,
+ const char *raw_pdu, size_t raw_pdu_len),
+ (circuit, lsp_id, raw_pdu, raw_pdu_len));
+DEFINE_HOOK(isis_hook_seqno_skipped,
+ (const struct isis_circuit *circuit, const uint8_t *lsp_id),
+ (circuit, lsp_id));
+DEFINE_HOOK(isis_hook_own_lsp_purge,
+ (const struct isis_circuit *circuit, const uint8_t *lsp_id),
+ (circuit, lsp_id));
+
+
/*
* Helper functions.
*/
@@ -92,7 +142,7 @@ void isis_notif_db_overload(const struct isis_area *area, bool overload)
* XPath: /frr-isisd:lsp-too-large
*/
void isis_notif_lsp_too_large(const struct isis_circuit *circuit,
- uint32_t pdu_size, const char *lsp_id)
+ uint32_t pdu_size, const uint8_t *lsp_id)
{
const char *xpath = "/frr-isisd:lsp-too-large";
struct list *arguments = yang_data_list_new();
@@ -106,9 +156,11 @@ void isis_notif_lsp_too_large(const struct isis_circuit *circuit,
data = yang_data_new_uint32(xpath_arg, pdu_size);
listnode_add(arguments, data);
snprintf(xpath_arg, sizeof(xpath_arg), "%s/lsp-id", xpath);
- data = yang_data_new_string(xpath_arg, lsp_id);
+ data = yang_data_new_string(xpath_arg, rawlspid_print(lsp_id));
listnode_add(arguments, data);
+ hook_call(isis_hook_lsp_too_large, circuit, pdu_size, lsp_id);
+
nb_notification_send(xpath, arguments);
}
@@ -135,7 +187,8 @@ void isis_notif_if_state_change(const struct isis_circuit *circuit, bool down)
/*
* XPath: /frr-isisd:corrupted-lsp-detected
*/
-void isis_notif_corrupted_lsp(const struct isis_area *area, const char *lsp_id)
+void isis_notif_corrupted_lsp(const struct isis_area *area,
+ const uint8_t *lsp_id)
{
const char *xpath = "/frr-isisd:corrupted-lsp-detected";
struct list *arguments = yang_data_list_new();
@@ -144,16 +197,19 @@ void isis_notif_corrupted_lsp(const struct isis_area *area, const char *lsp_id)
notif_prep_instance_hdr(xpath, area, "default", arguments);
snprintf(xpath_arg, sizeof(xpath_arg), "%s/lsp-id", xpath);
- data = yang_data_new_string(xpath_arg, lsp_id);
+ data = yang_data_new_string(xpath_arg, rawlspid_print(lsp_id));
listnode_add(arguments, data);
+ hook_call(isis_hook_corrupted_lsp, area);
+
nb_notification_send(xpath, arguments);
}
/*
* XPath: /frr-isisd:attempt-to-exceed-max-sequence
*/
-void isis_notif_lsp_exceed_max(const struct isis_area *area, const char *lsp_id)
+void isis_notif_lsp_exceed_max(const struct isis_area *area,
+ const uint8_t *lsp_id)
{
const char *xpath = "/frr-isisd:attempt-to-exceed-max-sequence";
struct list *arguments = yang_data_list_new();
@@ -162,9 +218,11 @@ void isis_notif_lsp_exceed_max(const struct isis_area *area, const char *lsp_id)
notif_prep_instance_hdr(xpath, area, "default", arguments);
snprintf(xpath_arg, sizeof(xpath_arg), "%s/lsp-id", xpath);
- data = yang_data_new_string(xpath_arg, lsp_id);
+ data = yang_data_new_string(xpath_arg, rawlspid_print(lsp_id));
listnode_add(arguments, data);
+ hook_call(isis_hook_lsp_exceed_max, area, lsp_id);
+
nb_notification_send(xpath, arguments);
}
@@ -173,7 +231,7 @@ void isis_notif_lsp_exceed_max(const struct isis_area *area, const char *lsp_id)
*/
void isis_notif_max_area_addr_mismatch(const struct isis_circuit *circuit,
uint8_t max_area_addrs,
- const char *raw_pdu)
+ const char *raw_pdu, size_t raw_pdu_len)
{
const char *xpath = "/frr-isisd:max-area-addresses-mismatch";
struct list *arguments = yang_data_list_new();
@@ -190,6 +248,9 @@ void isis_notif_max_area_addr_mismatch(const struct isis_circuit *circuit,
data = yang_data_new(xpath_arg, raw_pdu);
listnode_add(arguments, data);
+ hook_call(isis_hook_max_area_addr_mismatch, circuit, max_area_addrs,
+ raw_pdu, raw_pdu_len);
+
nb_notification_send(xpath, arguments);
}
@@ -197,7 +258,8 @@ void isis_notif_max_area_addr_mismatch(const struct isis_circuit *circuit,
* XPath: /frr-isisd:authentication-type-failure
*/
void isis_notif_authentication_type_failure(const struct isis_circuit *circuit,
- const char *raw_pdu)
+ const char *raw_pdu,
+ size_t raw_pdu_len)
{
const char *xpath = "/frr-isisd:authentication-type-failure";
struct list *arguments = yang_data_list_new();
@@ -211,6 +273,9 @@ void isis_notif_authentication_type_failure(const struct isis_circuit *circuit,
data = yang_data_new(xpath_arg, raw_pdu);
listnode_add(arguments, data);
+ hook_call(isis_hook_authentication_type_failure, circuit, raw_pdu,
+ raw_pdu_len);
+
nb_notification_send(xpath, arguments);
}
@@ -218,7 +283,7 @@ void isis_notif_authentication_type_failure(const struct isis_circuit *circuit,
* XPath: /frr-isisd:authentication-failure
*/
void isis_notif_authentication_failure(const struct isis_circuit *circuit,
- const char *raw_pdu)
+ const char *raw_pdu, size_t raw_pdu_len)
{
const char *xpath = "/frr-isisd:authentication-failure";
struct list *arguments = yang_data_list_new();
@@ -232,6 +297,9 @@ void isis_notif_authentication_failure(const struct isis_circuit *circuit,
data = yang_data_new(xpath_arg, raw_pdu);
listnode_add(arguments, data);
+ hook_call(isis_hook_authentication_failure, circuit, raw_pdu,
+ raw_pdu_len);
+
nb_notification_send(xpath, arguments);
}
@@ -269,6 +337,8 @@ void isis_notif_adj_state_change(const struct isis_adjacency *adj,
listnode_add(arguments, data);
}
+ hook_call(isis_hook_adj_state_change, adj);
+
nb_notification_send(xpath, arguments);
}
@@ -276,7 +346,8 @@ void isis_notif_adj_state_change(const struct isis_adjacency *adj,
* XPath: /frr-isisd:rejected-adjacency
*/
void isis_notif_reject_adjacency(const struct isis_circuit *circuit,
- const char *reason, const char *raw_pdu)
+ const char *reason, const char *raw_pdu,
+ size_t raw_pdu_len)
{
const char *xpath = "/frr-isisd:rejected-adjacency";
struct list *arguments = yang_data_list_new();
@@ -293,6 +364,8 @@ void isis_notif_reject_adjacency(const struct isis_circuit *circuit,
data = yang_data_new(xpath_arg, raw_pdu);
listnode_add(arguments, data);
+ hook_call(isis_hook_reject_adjacency, circuit, raw_pdu, raw_pdu_len);
+
nb_notification_send(xpath, arguments);
}
@@ -300,7 +373,7 @@ void isis_notif_reject_adjacency(const struct isis_circuit *circuit,
* XPath: /frr-isisd:area-mismatch
*/
void isis_notif_area_mismatch(const struct isis_circuit *circuit,
- const char *raw_pdu)
+ const char *raw_pdu, size_t raw_pdu_len)
{
const char *xpath = "/frr-isisd:area-mismatch";
struct list *arguments = yang_data_list_new();
@@ -314,6 +387,8 @@ void isis_notif_area_mismatch(const struct isis_circuit *circuit,
data = yang_data_new(xpath_arg, raw_pdu);
listnode_add(arguments, data);
+ hook_call(isis_hook_area_mismatch, circuit, raw_pdu, raw_pdu_len);
+
nb_notification_send(xpath, arguments);
}
@@ -321,7 +396,7 @@ void isis_notif_area_mismatch(const struct isis_circuit *circuit,
* XPath: /frr-isisd:lsp-received
*/
void isis_notif_lsp_received(const struct isis_circuit *circuit,
- const char *lsp_id, uint32_t seqno,
+ const uint8_t *lsp_id, uint32_t seqno,
uint32_t timestamp, const char *sys_id)
{
const char *xpath = "/frr-isisd:lsp-received";
@@ -333,7 +408,7 @@ void isis_notif_lsp_received(const struct isis_circuit *circuit,
notif_prep_instance_hdr(xpath, area, "default", arguments);
notif_prepr_iface_hdr(xpath, circuit, arguments);
snprintf(xpath_arg, sizeof(xpath_arg), "%s/lsp-id", xpath);
- data = yang_data_new_string(xpath_arg, lsp_id);
+ data = yang_data_new_string(xpath_arg, rawlspid_print(lsp_id));
listnode_add(arguments, data);
snprintf(xpath_arg, sizeof(xpath_arg), "%s/sequence", xpath);
data = yang_data_new_uint32(xpath_arg, seqno);
@@ -351,7 +426,7 @@ void isis_notif_lsp_received(const struct isis_circuit *circuit,
/*
* XPath: /frr-isisd:lsp-generation
*/
-void isis_notif_lsp_gen(const struct isis_area *area, const char *lsp_id,
+void isis_notif_lsp_gen(const struct isis_area *area, const uint8_t *lsp_id,
uint32_t seqno, uint32_t timestamp)
{
const char *xpath = "/frr-isisd:lsp-generation";
@@ -361,7 +436,7 @@ void isis_notif_lsp_gen(const struct isis_area *area, const char *lsp_id,
notif_prep_instance_hdr(xpath, area, "default", arguments);
snprintf(xpath_arg, sizeof(xpath_arg), "%s/lsp-id", xpath);
- data = yang_data_new_string(xpath_arg, lsp_id);
+ data = yang_data_new_string(xpath_arg, rawlspid_print(lsp_id));
listnode_add(arguments, data);
snprintf(xpath_arg, sizeof(xpath_arg), "%s/sequence", xpath);
data = yang_data_new_uint32(xpath_arg, seqno);
@@ -377,7 +452,8 @@ void isis_notif_lsp_gen(const struct isis_area *area, const char *lsp_id,
* XPath: /frr-isisd:id-len-mismatch
*/
void isis_notif_id_len_mismatch(const struct isis_circuit *circuit,
- uint8_t rcv_id_len, const char *raw_pdu)
+ uint8_t rcv_id_len, const char *raw_pdu,
+ size_t raw_pdu_len)
{
const char *xpath = "/frr-isisd:id-len-mismatch";
struct list *arguments = yang_data_list_new();
@@ -394,6 +470,9 @@ void isis_notif_id_len_mismatch(const struct isis_circuit *circuit,
data = yang_data_new(xpath_arg, raw_pdu);
listnode_add(arguments, data);
+ hook_call(isis_hook_id_len_mismatch, circuit, rcv_id_len, raw_pdu,
+ raw_pdu_len);
+
nb_notification_send(xpath, arguments);
}
@@ -401,7 +480,8 @@ void isis_notif_id_len_mismatch(const struct isis_circuit *circuit,
* XPath: /frr-isisd:version-skew
*/
void isis_notif_version_skew(const struct isis_circuit *circuit,
- uint8_t version, const char *raw_pdu)
+ uint8_t version, const char *raw_pdu,
+ size_t raw_pdu_len)
{
const char *xpath = "/frr-isisd:version-skew";
struct list *arguments = yang_data_list_new();
@@ -418,6 +498,9 @@ void isis_notif_version_skew(const struct isis_circuit *circuit,
data = yang_data_new(xpath_arg, raw_pdu);
listnode_add(arguments, data);
+ hook_call(isis_hook_version_skew, circuit, version, raw_pdu,
+ raw_pdu_len);
+
nb_notification_send(xpath, arguments);
}
@@ -425,7 +508,8 @@ void isis_notif_version_skew(const struct isis_circuit *circuit,
* XPath: /frr-isisd:lsp-error-detected
*/
void isis_notif_lsp_error(const struct isis_circuit *circuit,
- const char *lsp_id, const char *raw_pdu,
+ const uint8_t *lsp_id, const char *raw_pdu,
+ size_t raw_pdu_len,
__attribute__((unused)) uint32_t offset,
__attribute__((unused)) uint8_t tlv_type)
{
@@ -438,13 +522,15 @@ void isis_notif_lsp_error(const struct isis_circuit *circuit,
notif_prep_instance_hdr(xpath, area, "default", arguments);
notif_prepr_iface_hdr(xpath, circuit, arguments);
snprintf(xpath_arg, sizeof(xpath_arg), "%s/lsp-id", xpath);
- data = yang_data_new_string(xpath_arg, lsp_id);
+ data = yang_data_new_string(xpath_arg, rawlspid_print(lsp_id));
listnode_add(arguments, data);
snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath);
data = yang_data_new(xpath_arg, raw_pdu);
listnode_add(arguments, data);
/* ignore offset and tlv_type which cannot be set properly */
+ hook_call(isis_hook_lsp_error, circuit, lsp_id, raw_pdu, raw_pdu_len);
+
nb_notification_send(xpath, arguments);
}
@@ -452,7 +538,7 @@ void isis_notif_lsp_error(const struct isis_circuit *circuit,
* XPath: /frr-isisd:sequence-number-skipped
*/
void isis_notif_seqno_skipped(const struct isis_circuit *circuit,
- const char *lsp_id)
+ const uint8_t *lsp_id)
{
const char *xpath = "/frr-isisd:sequence-number-skipped";
struct list *arguments = yang_data_list_new();
@@ -463,9 +549,11 @@ void isis_notif_seqno_skipped(const struct isis_circuit *circuit,
notif_prep_instance_hdr(xpath, area, "default", arguments);
notif_prepr_iface_hdr(xpath, circuit, arguments);
snprintf(xpath_arg, sizeof(xpath_arg), "%s/lsp-id", xpath);
- data = yang_data_new_string(xpath_arg, lsp_id);
+ data = yang_data_new_string(xpath_arg, rawlspid_print(lsp_id));
listnode_add(arguments, data);
+ hook_call(isis_hook_seqno_skipped, circuit, lsp_id);
+
nb_notification_send(xpath, arguments);
}
@@ -473,7 +561,7 @@ void isis_notif_seqno_skipped(const struct isis_circuit *circuit,
* XPath: /frr-isisd:own-lsp-purge
*/
void isis_notif_own_lsp_purge(const struct isis_circuit *circuit,
- const char *lsp_id)
+ const uint8_t *lsp_id)
{
const char *xpath = "/frr-isisd:own-lsp-purge";
struct list *arguments = yang_data_list_new();
@@ -484,8 +572,10 @@ void isis_notif_own_lsp_purge(const struct isis_circuit *circuit,
notif_prep_instance_hdr(xpath, area, "default", arguments);
notif_prepr_iface_hdr(xpath, circuit, arguments);
snprintf(xpath_arg, sizeof(xpath_arg), "%s/lsp-id", xpath);
- data = yang_data_new_string(xpath_arg, lsp_id);
+ data = yang_data_new_string(xpath_arg, rawlspid_print(lsp_id));
listnode_add(arguments, data);
+ hook_call(isis_hook_own_lsp_purge, circuit, lsp_id);
+
nb_notification_send(xpath, arguments);
}
diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c
index a02b48157f..7256fcbbc7 100644
--- a/isisd/isis_pdu.c
+++ b/isisd/isis_pdu.c
@@ -549,6 +549,19 @@ static int pdu_len_validate(uint16_t pdu_len, struct isis_circuit *circuit)
return 0;
}
+static void update_rej_adj_count(struct isis_circuit *circuit)
+{
+ circuit->rej_adjacencies++;
+ if (circuit->is_type == IS_LEVEL_1)
+ circuit->area->rej_adjacencies[0]++;
+ else if (circuit->is_type == IS_LEVEL_2)
+ circuit->area->rej_adjacencies[1]++;
+ else {
+ circuit->area->rej_adjacencies[0]++;
+ circuit->area->rej_adjacencies[1]++;
+ }
+}
+
static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
uint8_t *ssnpa)
{
@@ -581,22 +594,22 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
if (p2p_hello) {
if (circuit->circ_type != CIRCUIT_T_P2P) {
zlog_warn("p2p hello on non p2p circuit");
- circuit->rej_adjacencies++;
+ update_rej_adj_count(circuit);
#ifndef FABRICD
isis_notif_reject_adjacency(
circuit, "p2p hello on non p2p circuit",
- raw_pdu);
+ raw_pdu, sizeof(raw_pdu));
#endif /* ifndef FABRICD */
return ISIS_WARNING;
}
} else {
if (circuit->circ_type != CIRCUIT_T_BROADCAST) {
zlog_warn("lan hello on non broadcast circuit");
- circuit->rej_adjacencies++;
+ update_rej_adj_count(circuit);
#ifndef FABRICD
isis_notif_reject_adjacency(
circuit, "lan hello on non broadcast circuit",
- raw_pdu);
+ raw_pdu, sizeof(raw_pdu));
#endif /* ifndef FABRICD */
return ISIS_WARNING;
}
@@ -605,12 +618,12 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
zlog_debug(
"level %d LAN Hello received over circuit with externalDomain = true",
level);
- circuit->rej_adjacencies++;
+ update_rej_adj_count(circuit);
#ifndef FABRICD
isis_notif_reject_adjacency(
circuit,
"LAN Hello received over circuit with externalDomain = true",
- raw_pdu);
+ raw_pdu, sizeof(raw_pdu));
#endif /* ifndef FABRICD */
return ISIS_WARNING;
}
@@ -622,10 +635,11 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
circuit->area->area_tag,
circuit->interface->name);
}
- circuit->rej_adjacencies++;
+ update_rej_adj_count(circuit);
#ifndef FABRICD
- isis_notif_reject_adjacency(
- circuit, "Interface level mismatch", raw_pdu);
+ isis_notif_reject_adjacency(circuit,
+ "Interface level mismatch",
+ raw_pdu, sizeof(raw_pdu));
#endif /* ifndef FABRICD */
return ISIS_WARNING;
}
@@ -652,10 +666,10 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
"ISIS-Adj (%s): Rcvd %s from (%s) with invalid pdu length %hu",
circuit->area->area_tag, pdu_name,
circuit->interface->name, iih.pdu_len);
- circuit->rej_adjacencies++;
+ update_rej_adj_count(circuit);
#ifndef FABRICD
isis_notif_reject_adjacency(circuit, "Invalid PDU length",
- raw_pdu);
+ raw_pdu, sizeof(raw_pdu));
#endif /* ifndef FABRICD */
return ISIS_WARNING;
}
@@ -664,10 +678,11 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
flog_err(EC_ISIS_PACKET,
"Level %d LAN Hello with Circuit Type %d", level,
iih.circ_type);
- circuit->rej_adjacencies++;
+ update_rej_adj_count(circuit);
#ifndef FABRICD
- isis_notif_reject_adjacency(
- circuit, "LAN Hello with wrong IS-level", raw_pdu);
+ isis_notif_reject_adjacency(circuit,
+ "LAN Hello with wrong IS-level",
+ raw_pdu, sizeof(raw_pdu));
#endif /* ifndef FABRICD */
return ISIS_ERROR;
}
@@ -678,10 +693,10 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
if (isis_unpack_tlvs(STREAM_READABLE(circuit->rcv_stream),
circuit->rcv_stream, &iih.tlvs, &error_log)) {
zlog_warn("isis_unpack_tlvs() failed: %s", error_log);
- circuit->rej_adjacencies++;
+ update_rej_adj_count(circuit);
#ifndef FABRICD
isis_notif_reject_adjacency(circuit, "Failed to unpack TLVs",
- raw_pdu);
+ raw_pdu, sizeof(raw_pdu));
#endif /* ifndef FABRICD */
goto out;
}
@@ -690,17 +705,18 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
zlog_warn("No Area addresses TLV in %s", pdu_name);
#ifndef FABRICD
/* send northbound notification */
- isis_notif_area_mismatch(circuit, raw_pdu);
+ isis_notif_area_mismatch(circuit, raw_pdu, sizeof(raw_pdu));
#endif /* ifndef FABRICD */
goto out;
}
if (!iih.tlvs->protocols_supported.count) {
zlog_warn("No supported protocols TLV in %s", pdu_name);
- circuit->rej_adjacencies++;
+ update_rej_adj_count(circuit);
#ifndef FABRICD
- isis_notif_reject_adjacency(
- circuit, "No supported protocols TLV", raw_pdu);
+ isis_notif_reject_adjacency(circuit,
+ "No supported protocols TLV",
+ raw_pdu, sizeof(raw_pdu));
#endif /* ifndef FABRICD */
goto out;
}
@@ -716,12 +732,13 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
stream_get_from(raw_pdu, circuit->rcv_stream, pdu_start,
pdu_end - pdu_start);
if (auth_code == ISIS_AUTH_FAILURE) {
- circuit->auth_failures++;
- isis_notif_authentication_failure(circuit, raw_pdu);
+ update_rej_adj_count(circuit);
+ isis_notif_authentication_failure(circuit, raw_pdu,
+ sizeof(raw_pdu));
} else { /* AUTH_TYPE_FAILURE or NO_VALIDATOR */
- circuit->auth_type_failures++;
- isis_notif_authentication_type_failure(circuit,
- raw_pdu);
+ update_rej_adj_count(circuit);
+ isis_notif_authentication_type_failure(circuit, raw_pdu,
+ sizeof(raw_pdu));
}
#endif /* ifndef FABRICD */
goto out;
@@ -731,10 +748,11 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
zlog_warn(
"ISIS-Adj (%s): Received IIH with own sysid on %s - discard",
circuit->area->area_tag, circuit->interface->name);
- circuit->rej_adjacencies++;
+ update_rej_adj_count(circuit);
#ifndef FABRICD
- isis_notif_reject_adjacency(
- circuit, "Received IIH with our own sysid", raw_pdu);
+ isis_notif_reject_adjacency(circuit,
+ "Received IIH with our own sysid",
+ raw_pdu, sizeof(raw_pdu));
#endif /* ifndef FABRICD */
goto out;
}
@@ -752,7 +770,7 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
}
#ifndef FABRICD
/* send northbound notification */
- isis_notif_area_mismatch(circuit, raw_pdu);
+ isis_notif_area_mismatch(circuit, raw_pdu, sizeof(raw_pdu));
#endif /* ifndef FABRICD */
goto out;
}
@@ -769,11 +787,11 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
"ISIS-Adj (%s): Neither IPv4 nor IPv6 considered usable. Ignoring IIH",
circuit->area->area_tag);
}
- circuit->rej_adjacencies++;
+ update_rej_adj_count(circuit);
#ifndef FABRICD
isis_notif_reject_adjacency(
circuit, "Neither IPv4 not IPv6 considered usable",
- raw_pdu);
+ raw_pdu, sizeof(raw_pdu));
#endif /* ifndef FABRICD */
goto out;
}
@@ -857,8 +875,8 @@ static int process_lsp(uint8_t pdu_type, struct isis_circuit *circuit,
#ifndef FABRICD
/* send northbound notification */
- isis_notif_lsp_received(circuit, rawlspid_print(hdr.lsp_id), hdr.seqno,
- time(NULL), sysid_print(hdr.lsp_id));
+ isis_notif_lsp_received(circuit, hdr.lsp_id, hdr.seqno, time(NULL),
+ sysid_print(hdr.lsp_id));
#endif /* ifndef FABRICD */
if (pdu_len_validate(hdr.pdu_len, circuit)) {
@@ -931,8 +949,18 @@ static int process_lsp(uint8_t pdu_type, struct isis_circuit *circuit,
* we change the code above to return those extra fields, we
* will send dummy values which are ignored in the callback
*/
- isis_notif_lsp_error(circuit, rawlspid_print(hdr.lsp_id),
- raw_pdu, 0, 0);
+ circuit->lsp_error_counter++;
+ if (circuit->is_type == IS_LEVEL_1) {
+ circuit->area->lsp_error_counter[0]++;
+ } else if (circuit->is_type == IS_LEVEL_2) {
+ circuit->area->lsp_error_counter[1]++;
+ } else {
+ circuit->area->lsp_error_counter[0]++;
+ circuit->area->lsp_error_counter[1]++;
+ }
+
+ isis_notif_lsp_error(circuit, hdr.lsp_id, raw_pdu,
+ sizeof(raw_pdu), 0, 0);
#endif /* ifndef FABRICD */
goto out;
}
@@ -956,11 +984,28 @@ static int process_lsp(uint8_t pdu_type, struct isis_circuit *circuit,
/* send northbound notification */
if (auth_code == ISIS_AUTH_FAILURE) {
circuit->auth_failures++;
- isis_notif_authentication_failure(circuit, raw_pdu);
+ if (circuit->is_type == IS_LEVEL_1) {
+ circuit->area->auth_failures[0]++;
+ } else if (circuit->is_type == IS_LEVEL_2) {
+ circuit->area->auth_failures[1]++;
+ } else {
+ circuit->area->auth_failures[0]++;
+ circuit->area->auth_failures[1]++;
+ }
+ isis_notif_authentication_failure(circuit, raw_pdu,
+ sizeof(raw_pdu));
} else { /* AUTH_TYPE_FAILURE or NO_VALIDATOR */
circuit->auth_type_failures++;
- isis_notif_authentication_type_failure(circuit,
- raw_pdu);
+ if (circuit->is_type == IS_LEVEL_1) {
+ circuit->area->auth_type_failures[0]++;
+ } else if (circuit->is_type == IS_LEVEL_2) {
+ circuit->area->auth_type_failures[1]++;
+ } else {
+ circuit->area->auth_type_failures[0]++;
+ circuit->area->auth_type_failures[1]++;
+ }
+ isis_notif_authentication_type_failure(circuit, raw_pdu,
+ sizeof(raw_pdu));
}
#endif /* ifndef FABRICD */
goto out;
@@ -1105,10 +1150,10 @@ dontcheckadj:
if (lsp->hdr.seqno < hdr.seqno) {
/* send northbound
* notification */
+ circuit->area
+ ->lsp_seqno_skipped_counter++;
isis_notif_seqno_skipped(
- circuit,
- rawlspid_print(
- hdr.lsp_id));
+ circuit, hdr.lsp_id);
}
#endif /* ifndef FABRICD */
lsp_inc_seqno(lsp, hdr.seqno);
@@ -1129,8 +1174,7 @@ dontcheckadj:
/* our own LSP with 0 remaining life time */
#ifndef FABRICD
/* send northbound notification */
- isis_notif_own_lsp_purge(
- circuit, rawlspid_print(hdr.lsp_id));
+ isis_notif_own_lsp_purge(circuit, hdr.lsp_id);
#endif /* ifndef FABRICD */
}
}
@@ -1158,8 +1202,8 @@ dontcheckadj:
lsp_inc_seqno(lsp, hdr.seqno);
#ifndef FABRICD
/* send northbound notification */
- isis_notif_seqno_skipped(circuit,
- rawlspid_print(hdr.lsp_id));
+ circuit->area->lsp_seqno_skipped_counter++;
+ isis_notif_seqno_skipped(circuit, hdr.lsp_id);
#endif /* ifndef FABRICD */
if (IS_DEBUG_UPDATE_PACKETS) {
zlog_debug(
@@ -1388,12 +1432,28 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit,
pdu_end - pdu_start);
if (auth_code == ISIS_AUTH_FAILURE) {
circuit->auth_failures++;
- isis_notif_authentication_failure(circuit,
- raw_pdu);
+ if (circuit->is_type == IS_LEVEL_1) {
+ circuit->area->auth_failures[0]++;
+ } else if (circuit->is_type == IS_LEVEL_2) {
+ circuit->area->auth_failures[1]++;
+ } else {
+ circuit->area->auth_failures[0]++;
+ circuit->area->auth_failures[1]++;
+ }
+ isis_notif_authentication_failure(
+ circuit, raw_pdu, sizeof(raw_pdu));
} else { /* AUTH_TYPE_FAILURE or NO_VALIDATOR */
circuit->auth_type_failures++;
- isis_notif_authentication_type_failure(circuit,
- raw_pdu);
+ if (circuit->is_type == IS_LEVEL_1) {
+ circuit->area->auth_type_failures[0]++;
+ } else if (circuit->is_type == IS_LEVEL_2) {
+ circuit->area->auth_type_failures[1]++;
+ } else {
+ circuit->area->auth_type_failures[0]++;
+ circuit->area->auth_type_failures[1]++;
+ }
+ isis_notif_authentication_type_failure(
+ circuit, raw_pdu, sizeof(raw_pdu));
}
#endif /* ifndef FABRICD */
goto out;
@@ -1620,7 +1680,8 @@ int isis_handle_pdu(struct isis_circuit *circuit, uint8_t *ssnpa)
zlog_warn("Unsupported ISIS version %hhu", version1);
#ifndef FABRICD
/* send northbound notification */
- isis_notif_version_skew(circuit, version1, raw_pdu);
+ isis_notif_version_skew(circuit, version1, raw_pdu,
+ sizeof(raw_pdu));
#endif /* ifndef FABRICD */
return ISIS_WARNING;
}
@@ -1631,9 +1692,19 @@ int isis_handle_pdu(struct isis_circuit *circuit, uint8_t *ssnpa)
"IDFieldLengthMismatch: ID Length field in a received PDU %hhu, while the parameter for this IS is %u",
id_len, ISIS_SYS_ID_LEN);
circuit->id_len_mismatches++;
+ if (circuit->is_type == IS_LEVEL_1) {
+ circuit->area->id_len_mismatches[0]++;
+ } else if (circuit->is_type == IS_LEVEL_2) {
+ circuit->area->id_len_mismatches[1]++;
+ } else {
+ circuit->area->id_len_mismatches[0]++;
+ circuit->area->id_len_mismatches[1]++;
+ }
+
#ifndef FABRICD
/* send northbound notification */
- isis_notif_id_len_mismatch(circuit, id_len, raw_pdu);
+ isis_notif_id_len_mismatch(circuit, id_len, raw_pdu,
+ sizeof(raw_pdu));
#endif /* ifndef FABRICD */
return ISIS_ERROR;
}
@@ -1662,7 +1733,8 @@ int isis_handle_pdu(struct isis_circuit *circuit, uint8_t *ssnpa)
zlog_warn("Unsupported ISIS PDU version %hhu", version2);
#ifndef FABRICD
/* send northbound notification */
- isis_notif_version_skew(circuit, version2, raw_pdu);
+ isis_notif_version_skew(circuit, version2, raw_pdu,
+ sizeof(raw_pdu));
#endif /* ifndef FABRICD */
return ISIS_WARNING;
}
@@ -1686,7 +1758,7 @@ int isis_handle_pdu(struct isis_circuit *circuit, uint8_t *ssnpa)
#ifndef FABRICD
/* send northbound notification */
isis_notif_max_area_addr_mismatch(circuit, max_area_addrs,
- raw_pdu);
+ raw_pdu, sizeof(raw_pdu));
#endif /* ifndef FABRICD */
return ISIS_ERROR;
}
@@ -2409,7 +2481,7 @@ void send_lsp(struct isis_circuit *circuit, struct isis_lsp *lsp,
#ifndef FABRICD
/* send a northbound notification */
isis_notif_lsp_too_large(circuit, stream_get_endp(lsp->pdu),
- rawlspid_print(lsp->hdr.lsp_id));
+ lsp->hdr.lsp_id);
#endif /* ifndef FABRICD */
if (IS_DEBUG_PACKET_DUMP)
zlog_dump_data(STREAM_DATA(lsp->pdu),
diff --git a/isisd/isis_snmp.c b/isisd/isis_snmp.c
new file mode 100644
index 0000000000..cab9199731
--- /dev/null
+++ b/isisd/isis_snmp.c
@@ -0,0 +1,3457 @@
+/*
+ * ISIS SNMP support
+ * Copyright (C) 2020 Volta Networks, Inc.
+ * Aleksey Romanov
+ *
+ * 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 isisReadOnlyCompliance
+ */
+
+#include <zebra.h>
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+
+#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 "isisd/isis_constants.h"
+#include "isisd/isis_common.h"
+#include "isisd/isis_flags.h"
+#include "isisd/isis_circuit.h"
+#include "isisd/isis_lsp.h"
+#include "isisd/isis_pdu.h"
+#include "isisd/isis_network.h"
+#include "isisd/isis_misc.h"
+#include "isisd/isis_constants.h"
+#include "isisd/isis_adjacency.h"
+#include "isisd/isis_dynhn.h"
+#include "isisd/isis_te.h"
+#include "isisd/isis_dr.h"
+#include "isisd/isis_nb.h"
+#include "isisd/isisd.h"
+
+/* ISIS-MIB. */
+#define ISIS_MIB 1, 3, 6, 1, 2, 1, 138
+
+#define ISIS_OBJECTS 1
+#define ISIS_SYSTEM 1, 1
+#define ISIS_SYSLEVEL 1, 2
+#define ISIS_CIRC 1, 3
+#define ISIS_CIRC_LEVEL_VALUES 1, 4
+#define ISIS_COUNTERS 1, 5
+#define ISIS_ISADJ 1, 6
+
+/************************ isisSystemGroup ************************/
+
+/* isisSysObject */
+#define ISIS_SYS_OBJECT 1, 1, 1
+#define ISIS_SYS_VERSION 1
+#define ISIS_SYS_LEVELTYPE 2
+#define ISIS_SYS_ID 3
+#define ISIS_SYS_MAXPATHSPLITS 4
+#define ISIS_SYS_MAXLSPGENINT 5
+#define ISIS_SYS_POLLESHELLORATE 6
+#define ISIS_SYS_WAITTIME 7
+#define ISIS_SYS_ADMINSTATE 8
+#define ISIS_SYS_L2TOL1LEAKING 9
+#define ISIS_SYS_MAXAGE 10
+#define ISIS_SYS_RECEIVELSPBUFFERSIZE 11
+#define ISIS_SYS_PROTSUPPORTED 12
+#define ISIS_SYS_NOTIFICATIONENABLE 13
+
+/* isisManAreaAddrEntry */
+#define ISIS_MANAREA_ADDRENTRY 1, 1, 2, 1
+#define ISIS_MANAREA_ADDREXISTSTATE 2
+
+/* isisAreaAddrEntry */
+#define ISIS_AREA_ADDRENTRY 1, 1, 3, 1
+#define ISIS_AREA_ADDR 1
+
+/* isisSummAddrEntry */
+#define ISIS_SUMM_ADDRENTRY 1, 1, 4, 1
+#define ISIS_SUMM_ADDREXISTSTATE 4
+#define ISIS_SUMM_ADDRMETRIC 5
+#define ISIS_SUMM_ADDRFULLMETRIC 6
+
+/* isisRedistributeAddrEntry */
+#define ISIS_REDISTRIBUTE_ADDRENTRY 1, 1, 5, 1
+#define ISIS_REDISTRIBUTE_ADDREXISTSTATE 3
+
+/* isisRouterEntry */
+#define ISIS_ROUTER_ENTRY 1, 1, 6, 1
+#define ISIS_ROUTER_HOSTNAME 3
+#define ISIS_ROUTER_ID 4
+
+/* isisSysLevelTable */
+#define ISIS_SYSLEVEL_ENTRY 1, 2, 1, 1
+#define ISIS_SYSLEVEL_ORIGLSPBUFFSIZE 2
+#define ISIS_SYSLEVEL_MINLSPGENINT 3
+#define ISIS_SYSLEVEL_STATE 4
+#define ISIS_SYSLEVEL_SETOVERLOAD 5
+#define ISIS_SYSLEVEL_SETOVERLOADUNTIL 6
+#define ISIS_SYSLEVEL_METRICSTYLE 7
+#define ISIS_SYSLEVEL_SPFCONSIDERS 8
+#define ISIS_SYSLEVEL_TEENABLED 9
+
+
+/* isisSystemCounterEntry */
+#define ISIS_SYSTEM_COUNTER_ENTRY 1, 5, 1, 1
+#define ISIS_SYSSTAT_CORRLSPS 2
+#define ISIS_SYSSTAT_AUTHTYPEFAILS 3
+#define ISIS_SYSSTAT_AUTHFAILS 4
+#define ISIS_SYSSTAT_LSPDBASEOLOADS 5
+#define ISIS_SYSSTAT_MANADDRDROPFROMAREAS 6
+#define ISIS_SYSSTAT_ATTMPTTOEXMAXSEQNUMS 7
+#define ISIS_SYSSTAT_SEQNUMSKIPS 8
+#define ISIS_SYSSTAT_OWNLSPPURGES 9
+#define ISIS_SYSSTAT_IDFIELDLENMISMATCHES 10
+#define ISIS_SYSSTAT_PARTCHANGES 11
+#define ISIS_SYSSTAT_SPFRUNS 12
+#define ISIS_SYSSTAT_LSPERRORS 13
+
+
+/************************ isisCircuitGroup ************************/
+
+/* Scalar directly under isisCirc */
+#define ISIS_NEXTCIRC_INDEX 1
+
+/* isisCircEntry */
+#define ISIS_CIRC_ENTRY 1, 3, 2, 1
+#define ISIS_CIRC_IFINDEX 2
+#define ISIS_CIRC_ADMINSTATE 3
+#define ISIS_CIRC_EXISTSTATE 4
+#define ISIS_CIRC_TYPE 5
+#define ISIS_CIRC_EXTDOMAIN 6
+#define ISIS_CIRC_LEVELTYPE 7
+#define ISIS_CIRC_PASSIVECIRCUIT 8
+#define ISIS_CIRC_MESHGROUPENABLED 9
+#define ISIS_CIRC_MESHGROUP 10
+#define ISIS_CIRC_SMALLHELLOS 11
+#define ISIS_CIRC_LASTUPTIME 12
+#define ISIS_CIRC_3WAYENABLED 13
+#define ISIS_CIRC_EXTENDEDCIRCID 14
+
+/* isisCircLevelEntry */
+#define ISIS_CIRCLEVEL_ENTRY 1, 4, 1, 1
+#define ISIS_CIRCLEVEL_METRIC 2
+#define ISIS_CIRCLEVEL_WIDEMETRIC 3
+#define ISIS_CIRCLEVEL_ISPRIORITY 4
+#define ISIS_CIRCLEVEL_IDOCTET 5
+#define ISIS_CIRCLEVEL_ID 6
+#define ISIS_CIRCLEVEL_DESIS 7
+#define ISIS_CIRCLEVEL_HELLOMULTIPLIER 8
+#define ISIS_CIRCLEVEL_HELLOTIMER 9
+#define ISIS_CIRCLEVEL_DRHELLOTIMER 10
+#define ISIS_CIRCLEVEL_LSPTHROTTLE 11
+#define ISIS_CIRCLEVEL_MINLSPRETRANSINT 12
+#define ISIS_CIRCLEVEL_CSNPINTERVAL 13
+#define ISIS_CIRCLEVEL_PARTSNPINTERVAL 14
+
+/* isisCircuitCounterEntry */
+#define ISIS_CIRC_COUNTER_ENTRY 1, 5, 2, 1
+#define ISIS_CIRC_ADJCHANGES 2
+#define ISIS_CIRC_NUMADJ 3
+#define ISIS_CIRC_INITFAILS 4
+#define ISIS_CIRC_REJADJS 5
+#define ISIS_CIRC_IDFIELDLENMISMATCHES 6
+#define ISIS_CIRC_MAXAREAADDRMISMATCHES 7
+#define ISIS_CIRC_AUTHTYPEFAILS 8
+#define ISIS_CIRC_AUTHFAILS 9
+#define ISIS_CIRC_LANDESISCHANGES 10
+
+
+/************************ isisISAdjGroup ************************/
+
+/* isisISAdjEntry */
+#define ISIS_ISADJ_ENTRY 1, 6, 1, 1
+#define ISIS_ISADJ_STATE 2
+#define ISIS_ISADJ_3WAYSTATE 3
+#define ISIS_ISADJ_NEIGHSNPAADDRESS 4
+#define ISIS_ISADJ_NEIGHSYSTYPE 5
+#define ISIS_ISADJ_NEIGHSYSID 6
+#define ISIS_ISADJ_NBREXTENDEDCIRCID 7
+#define ISIS_ISADJ_USAGE 8
+#define ISIS_ISADJ_HOLDTIMER 9
+#define ISIS_ISADJ_NEIGHPRIORITY 10
+#define ISIS_ISADJ_LASTUPTIME 11
+
+/* isisISAdjAreadAddrEntry */
+#define ISIS_ISADJAREA_ADDRENTRY 1, 6, 2, 1
+#define ISIS_ISADJAREA_ADDRESS 2
+
+/* isisISAdjIPAddrEntry*/
+#define ISIS_ISADJIPADDR_ENTRY 1, 6, 3, 1
+#define ISIS_ISADJIPADDR_TYPE 2
+#define ISIS_ISADJIPADDR_ADDRESS 3
+
+
+/* isisISAdjProtSuppEntty */
+
+#define ISIS_ISADJPROTSUPP_ENTRY 1, 6, 4, 1
+#define ISIS_ISADJPROTSUPP_PROTOCOL 1
+
+
+/************************ Trap data variables ************************/
+#define ISIS_NOTIFICATION_ENTRY 1, 10, 1
+#define ISIS_NOTIF_SYLELVELINDEX 1
+#define ISIS_NOTIF_CIRCIFINDEX 2
+#define ISIS_PDU_LSPID 3
+#define ISIS_PDU_FRAGMENT 4
+#define ISIS_PDU_FIELDLEN 5
+#define ISIS_PDU_MAXAREAADDR 6
+#define ISIS_PDU_PROTOVER 7
+#define ISIS_PDU_LSPSIZE 8
+#define ISIS_PDU_ORIGBUFFERSIZE 9
+#define ISIS_PDU_BUFFERSIZE 10
+#define ISIS_PDU_PROTSUPP 11
+#define ISIS_ADJ_STATE 12
+#define ISIS_ERROR_OFFSET 13
+#define ISIS_ERROR_TLVTYPE 14
+#define ISIS_NOTIF_AREAADDR 15
+
+/************************ Traps ************************/
+#define ISIS_NOTIFICATIONS ISIS_MIB, 0
+#define ISIS_TRAP_DB_OVERLOAD 1
+#define ISIS_TRAP_MAN_ADDR_DROP 2
+#define ISIS_TRAP_CORRUPTED_LSP 3
+#define ISIS_TRAP_LSP_EXCEED_MAX 4
+#define ISIS_TRAP_ID_LEN_MISMATCH 5
+#define ISIS_TRAP_MAX_AREA_ADDR_MISMATCH 6
+#define ISIS_TRAP_OWN_LSP_PURGE 7
+#define ISIS_TRAP_SEQNO_SKIPPED 8
+#define ISIS_TRAP_AUTHEN_TYPE_FAILURE 9
+#define ISIS_TRAP_AUTHEN_FAILURE 10
+#define ISIS_TRAP_VERSION_SKEW 11
+#define ISIS_TRAP_AREA_MISMATCH 12
+#define ISIS_TRAP_REJ_ADJACENCY 13
+#define ISIS_TRAP_LSP_TOO_LARGE 14
+#define ISIS_TRAP_LSP_BUFFSIZE_MISMATCH 15
+#define ISIS_TRAP_PROTSUPP_MISMATCH 16
+#define ISIS_TRAP_ADJ_STATE_CHANGE 17
+#define ISIS_TRAP_LSP_ERROR 18
+
+/* Change this definition if number of traps changes */
+#define ISIS_TRAP_LAST_TRAP ISIS_TRAP_LSP_ERROR
+
+#define ISIS_SNMP_TRAP_VAR 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0
+
+
+/* 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
+
+/* Declare static local variables for convenience. */
+SNMP_LOCAL_VARIABLES
+
+/* If ARRAY_SIZE is not available use a primitive substitution */
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+#endif
+
+/*
+ * Define time function, it serves two purposes
+ * 1. Uses unint32_t for unix time and encapsulates
+ * sing extension issues in conversion from time_t
+ *
+ * 2. I could be replaced in unit test environment
+ */
+#ifndef ISIS_SNMP_HAVE_TIME_FUNC
+static uint32_t isis_snmp_time(void)
+{
+ return (uint32_t)time(NULL);
+}
+
+#endif
+
+/* ISIS-MIB instances. */
+static oid isis_oid[] = {ISIS_MIB};
+
+/* SNMP trap variable */
+static oid isis_snmp_trap_var[] = {ISIS_SNMP_TRAP_VAR};
+
+/* SNMP trap values (others are calculated on the fly */
+static oid isis_snmp_notifications[] = {ISIS_NOTIFICATIONS};
+static oid isis_snmp_trap_val_db_overload[] = {ISIS_NOTIFICATIONS,
+ ISIS_TRAP_DB_OVERLOAD};
+static oid isis_snmp_trap_val_lsp_exceed_max[] = {ISIS_NOTIFICATIONS,
+ ISIS_TRAP_LSP_EXCEED_MAX};
+static oid isis_snmp_trap_val_area_mismatch[] = {ISIS_NOTIFICATIONS,
+ ISIS_TRAP_AREA_MISMATCH};
+static oid isis_snmp_trap_val_lsp_error[] = {ISIS_NOTIFICATIONS,
+ ISIS_TRAP_LSP_ERROR};
+
+/*
+ * Trap vars under 'isisNotifications': note: we use full names of variables
+ * scalar index
+ */
+static oid isis_snmp_trap_data_var_sys_level_index[] = {
+ ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_NOTIF_SYLELVELINDEX, 0};
+static oid isis_snmp_trap_data_var_circ_if_index[] = {
+ ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_NOTIF_CIRCIFINDEX, 0};
+static oid isis_snmp_trap_data_var_pdu_lsp_id[] = {
+ ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_PDU_LSPID, 0};
+static oid isis_snmp_trap_data_var_pdu_fragment[] = {
+ ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_PDU_FRAGMENT, 0};
+static oid isis_snmp_trap_data_var_pdu_field_len[] = {
+ ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_PDU_FIELDLEN, 0};
+static oid isis_snmp_trap_data_var_pdu_max_area_addr[] = {
+ ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_PDU_MAXAREAADDR, 0};
+static oid isis_snmp_trap_data_var_pdu_proto_ver[] = {
+ ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_PDU_PROTOVER, 0};
+static oid isis_snmp_trap_data_var_pdu_lsp_size[] = {
+ ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_PDU_LSPSIZE, 0};
+static oid isis_snmp_trap_data_var_adj_state[] = {
+ ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_ADJ_STATE, 0};
+static oid isis_snmp_trap_data_var_error_offset[] = {
+ ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_ERROR_OFFSET, 0};
+static oid isis_snmp_trap_data_var_error_tlv_type[] = {
+ ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_ERROR_TLVTYPE, 0};
+
+/*
+ * Other variables used by traps: note we use full names of variables and
+ * reserve space for index
+ */
+static oid isis_snmp_trap_data_var_sys_level_state[] = {
+ ISIS_MIB, ISIS_SYSLEVEL_ENTRY, ISIS_SYSLEVEL_STATE, 0};
+
+/* Throttle time values for traps */
+static time_t isis_snmp_trap_timestamp[ISIS_TRAP_LAST_TRAP]; /* ?? 1 */
+
+/* Max len of raw-pdu in traps */
+#define ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN (64)
+
+/*
+ * Just to save on typing we have a shortcut structure
+ * to specify mib layout as prefix/leaf combination
+ */
+#define ISIS_SNMP_PREF_LEN_MAX 10
+struct isis_var_prefix {
+ FindVarMethod *findVar;
+ uint8_t ivd_pref_len;
+ oid ivd_pref[ISIS_SNMP_PREF_LEN_MAX];
+};
+
+
+/* Find-val functions */
+static uint8_t *isis_snmp_find_sys_object(struct variable *, oid *, size_t *,
+ int, size_t *, WriteMethod **);
+
+static uint8_t *isis_snmp_find_man_area(struct variable *, oid *, size_t *, int,
+ size_t *, WriteMethod **);
+
+static uint8_t *isis_snmp_find_area_addr(struct variable *, oid *, size_t *,
+ int, size_t *, WriteMethod **);
+
+static uint8_t *isis_snmp_find_summ_addr(struct variable *, oid *, size_t *,
+ int, size_t *, WriteMethod **);
+
+static uint8_t *isis_snmp_find_redistribute_addr(struct variable *, oid *,
+ size_t *, int, size_t *,
+ WriteMethod **);
+
+static uint8_t *isis_snmp_find_router(struct variable *, oid *, size_t *, int,
+ size_t *, WriteMethod **);
+
+static uint8_t *isis_snmp_find_sys_level(struct variable *, oid *, size_t *,
+ int, size_t *, WriteMethod **);
+
+static uint8_t *isis_snmp_find_system_counter(struct variable *, oid *,
+ size_t *, int, size_t *,
+ WriteMethod **);
+
+static uint8_t *isis_snmp_find_next_circ_index(struct variable *, oid *,
+ size_t *, int, size_t *,
+ WriteMethod **);
+
+static uint8_t *isis_snmp_find_circ(struct variable *, oid *, size_t *, int,
+ size_t *, WriteMethod **);
+
+static uint8_t *isis_snmp_find_circ_level(struct variable *, oid *, size_t *,
+ int, size_t *, WriteMethod **);
+
+static uint8_t *isis_snmp_find_circ_counter(struct variable *, oid *, size_t *,
+ int, size_t *, WriteMethod **);
+
+static uint8_t *isis_snmp_find_isadj(struct variable *, oid *, size_t *, int,
+ size_t *, WriteMethod **);
+
+static uint8_t *isis_snmp_find_isadj_area(struct variable *, oid *, size_t *,
+ int, size_t *, WriteMethod **);
+
+static uint8_t *isis_snmp_find_isadj_ipaddr(struct variable *, oid *, size_t *,
+ int, size_t *, WriteMethod **);
+
+static uint8_t *isis_snmp_find_isadj_prot_supp(struct variable *, oid *,
+ size_t *, int, size_t *,
+ WriteMethod **);
+
+/*
+ * Just to save on typing we have a shortcut structure
+ * to specify mib layout, we populate the rest of the data
+ * during initialization
+ */
+#define ISIS_PREF_LEN_MAX (6)
+
+struct isis_func_to_prefix {
+ FindVarMethod *ihtp_func;
+ oid ihtp_pref_oid[ISIS_PREF_LEN_MAX];
+ uint8_t ihtp_pref_len;
+};
+
+static struct isis_func_to_prefix isis_func_to_prefix_arr[] = {
+ {isis_snmp_find_sys_object, {ISIS_SYS_OBJECT}, 3},
+ {isis_snmp_find_man_area, {ISIS_MANAREA_ADDRENTRY}, 4},
+ {isis_snmp_find_area_addr, {ISIS_AREA_ADDRENTRY}, 4},
+ {isis_snmp_find_summ_addr, {ISIS_SUMM_ADDRENTRY}, 4},
+ {isis_snmp_find_redistribute_addr, {ISIS_REDISTRIBUTE_ADDRENTRY}, 4},
+ {isis_snmp_find_router, {ISIS_ROUTER_ENTRY}, 4},
+ {isis_snmp_find_sys_level, {ISIS_SYSLEVEL_ENTRY}, 4},
+ {isis_snmp_find_system_counter, {ISIS_SYSTEM_COUNTER_ENTRY}, 4},
+ {isis_snmp_find_next_circ_index, {ISIS_CIRC}, 2},
+ {isis_snmp_find_circ, {ISIS_CIRC_ENTRY}, 4},
+ {isis_snmp_find_circ_level, {ISIS_CIRCLEVEL_ENTRY}, 4},
+ {isis_snmp_find_circ_counter, {ISIS_CIRC_COUNTER_ENTRY}, 4},
+ {isis_snmp_find_isadj, {ISIS_ISADJ_ENTRY}, 4},
+ {isis_snmp_find_isadj_area, {ISIS_ISADJAREA_ADDRENTRY}, 4},
+ {isis_snmp_find_isadj_ipaddr, {ISIS_ISADJIPADDR_ENTRY}, 4},
+ {isis_snmp_find_isadj_prot_supp, {ISIS_ISADJPROTSUPP_ENTRY}, 4},
+};
+static size_t isis_func_to_prefix_count = ARRAY_SIZE(isis_func_to_prefix_arr);
+
+static struct variable isis_var_arr[] = {
+ {ISIS_SYS_VERSION, INTEGER, RONLY, isis_snmp_find_sys_object},
+ {ISIS_SYS_LEVELTYPE, INTEGER, RONLY, isis_snmp_find_sys_object},
+ {ISIS_SYS_ID, STRING, RONLY, isis_snmp_find_sys_object},
+ {ISIS_SYS_MAXPATHSPLITS, UNSIGNED32, RONLY, isis_snmp_find_sys_object},
+ {ISIS_SYS_MAXLSPGENINT, UNSIGNED32, RONLY, isis_snmp_find_sys_object},
+ {ISIS_SYS_POLLESHELLORATE, UNSIGNED32, RONLY,
+ isis_snmp_find_sys_object},
+ {ISIS_SYS_WAITTIME, UNSIGNED32, RONLY, isis_snmp_find_sys_object},
+ {ISIS_SYS_ADMINSTATE, INTEGER, RONLY, isis_snmp_find_sys_object},
+ {ISIS_SYS_L2TOL1LEAKING, INTEGER, RONLY, isis_snmp_find_sys_object},
+ {ISIS_SYS_MAXAGE, UNSIGNED32, RONLY, isis_snmp_find_sys_object},
+ {ISIS_SYS_RECEIVELSPBUFFERSIZE, UNSIGNED32, RONLY,
+ isis_snmp_find_sys_object},
+ {ISIS_SYS_PROTSUPPORTED, STRING, RONLY, isis_snmp_find_sys_object},
+ {ISIS_SYS_NOTIFICATIONENABLE, INTEGER, RONLY,
+ isis_snmp_find_sys_object},
+ {ISIS_MANAREA_ADDREXISTSTATE, INTEGER, RONLY, isis_snmp_find_man_area},
+ {ISIS_AREA_ADDR, STRING, RONLY, isis_snmp_find_area_addr},
+ {ISIS_SUMM_ADDREXISTSTATE, INTEGER, RONLY, isis_snmp_find_summ_addr},
+ {ISIS_SUMM_ADDRMETRIC, UNSIGNED32, RONLY, isis_snmp_find_summ_addr},
+ {ISIS_SUMM_ADDRFULLMETRIC, UNSIGNED32, RONLY, isis_snmp_find_summ_addr},
+ {ISIS_REDISTRIBUTE_ADDREXISTSTATE, INTEGER, RONLY,
+ isis_snmp_find_redistribute_addr},
+ {ISIS_ROUTER_HOSTNAME, STRING, RONLY, isis_snmp_find_router},
+ {ISIS_ROUTER_ID, UNSIGNED32, RONLY, isis_snmp_find_router},
+ {ISIS_SYSLEVEL_ORIGLSPBUFFSIZE, UNSIGNED32, RONLY,
+ isis_snmp_find_sys_level},
+ {ISIS_SYSLEVEL_MINLSPGENINT, UNSIGNED32, RONLY,
+ isis_snmp_find_sys_level},
+ {ISIS_SYSLEVEL_STATE, INTEGER, RONLY, isis_snmp_find_sys_level},
+ {ISIS_SYSLEVEL_SETOVERLOAD, INTEGER, RONLY, isis_snmp_find_sys_level},
+ {ISIS_SYSLEVEL_SETOVERLOADUNTIL, UNSIGNED32, RONLY,
+ isis_snmp_find_sys_level},
+ {ISIS_SYSLEVEL_METRICSTYLE, INTEGER, RONLY, isis_snmp_find_sys_level},
+ {ISIS_SYSLEVEL_SPFCONSIDERS, INTEGER, RONLY, isis_snmp_find_sys_level},
+ {ISIS_SYSLEVEL_TEENABLED, INTEGER, RONLY, isis_snmp_find_sys_level},
+ {ISIS_SYSSTAT_CORRLSPS, COUNTER32, RONLY,
+ isis_snmp_find_system_counter},
+ {ISIS_SYSSTAT_AUTHTYPEFAILS, COUNTER32, RONLY,
+ isis_snmp_find_system_counter},
+ {ISIS_SYSSTAT_AUTHFAILS, COUNTER32, RONLY,
+ isis_snmp_find_system_counter},
+ {ISIS_SYSSTAT_LSPDBASEOLOADS, COUNTER32, RONLY,
+ isis_snmp_find_system_counter},
+ {ISIS_SYSSTAT_MANADDRDROPFROMAREAS, COUNTER32, RONLY,
+ isis_snmp_find_system_counter},
+ {ISIS_SYSSTAT_ATTMPTTOEXMAXSEQNUMS, COUNTER32, RONLY,
+ isis_snmp_find_system_counter},
+ {ISIS_SYSSTAT_SEQNUMSKIPS, COUNTER32, RONLY,
+ isis_snmp_find_system_counter},
+ {ISIS_SYSSTAT_OWNLSPPURGES, COUNTER32, RONLY,
+ isis_snmp_find_system_counter},
+ {ISIS_SYSSTAT_IDFIELDLENMISMATCHES, COUNTER32, RONLY,
+ isis_snmp_find_system_counter},
+ {ISIS_SYSSTAT_PARTCHANGES, COUNTER32, RONLY,
+ isis_snmp_find_system_counter},
+ {ISIS_SYSSTAT_SPFRUNS, COUNTER32, RONLY, isis_snmp_find_system_counter},
+ {ISIS_SYSSTAT_LSPERRORS, COUNTER32, RONLY,
+ isis_snmp_find_system_counter},
+ {ISIS_NEXTCIRC_INDEX, UNSIGNED32, RONLY,
+ isis_snmp_find_next_circ_index},
+ {ISIS_CIRC_IFINDEX, INTEGER, RONLY, isis_snmp_find_circ},
+ {ISIS_CIRC_ADMINSTATE, INTEGER, RONLY, isis_snmp_find_circ},
+ {ISIS_CIRC_EXISTSTATE, INTEGER, RONLY, isis_snmp_find_circ},
+ {ISIS_CIRC_TYPE, INTEGER, RONLY, isis_snmp_find_circ},
+ {ISIS_CIRC_EXTDOMAIN, INTEGER, RONLY, isis_snmp_find_circ},
+ {ISIS_CIRC_LEVELTYPE, INTEGER, RONLY, isis_snmp_find_circ},
+ {ISIS_CIRC_PASSIVECIRCUIT, INTEGER, RONLY, isis_snmp_find_circ},
+ {ISIS_CIRC_MESHGROUPENABLED, INTEGER, RONLY, isis_snmp_find_circ},
+ {ISIS_CIRC_MESHGROUP, UNSIGNED32, RONLY, isis_snmp_find_circ},
+ {ISIS_CIRC_SMALLHELLOS, INTEGER, RONLY, isis_snmp_find_circ},
+ {ISIS_CIRC_LASTUPTIME, TIMESTAMP, RONLY, isis_snmp_find_circ},
+ {ISIS_CIRC_3WAYENABLED, INTEGER, RONLY, isis_snmp_find_circ},
+ {ISIS_CIRC_EXTENDEDCIRCID, UNSIGNED32, RONLY, isis_snmp_find_circ},
+ {ISIS_CIRCLEVEL_METRIC, UNSIGNED32, RONLY, isis_snmp_find_circ_level},
+ {ISIS_CIRCLEVEL_WIDEMETRIC, UNSIGNED32, RONLY,
+ isis_snmp_find_circ_level},
+ {ISIS_CIRCLEVEL_ISPRIORITY, UNSIGNED32, RONLY,
+ isis_snmp_find_circ_level},
+ {ISIS_CIRCLEVEL_IDOCTET, UNSIGNED32, RONLY, isis_snmp_find_circ_level},
+ {ISIS_CIRCLEVEL_ID, STRING, RONLY, isis_snmp_find_circ_level},
+ {ISIS_CIRCLEVEL_DESIS, STRING, RONLY, isis_snmp_find_circ_level},
+ {ISIS_CIRCLEVEL_HELLOMULTIPLIER, UNSIGNED32, RONLY,
+ isis_snmp_find_circ_level},
+ {ISIS_CIRCLEVEL_HELLOTIMER, UNSIGNED32, RONLY,
+ isis_snmp_find_circ_level},
+ {ISIS_CIRCLEVEL_DRHELLOTIMER, UNSIGNED32, RONLY,
+ isis_snmp_find_circ_level},
+ {ISIS_CIRCLEVEL_LSPTHROTTLE, UNSIGNED32, RONLY,
+ isis_snmp_find_circ_level},
+ {ISIS_CIRCLEVEL_MINLSPRETRANSINT, UNSIGNED32, RONLY,
+ isis_snmp_find_circ_level},
+ {ISIS_CIRCLEVEL_CSNPINTERVAL, UNSIGNED32, RONLY,
+ isis_snmp_find_circ_level},
+ {ISIS_CIRCLEVEL_PARTSNPINTERVAL, UNSIGNED32, RONLY,
+ isis_snmp_find_circ_level},
+ {ISIS_CIRC_ADJCHANGES, COUNTER32, RONLY, isis_snmp_find_circ_counter},
+ {ISIS_CIRC_NUMADJ, UNSIGNED32, RONLY, isis_snmp_find_circ_counter},
+ {ISIS_CIRC_INITFAILS, COUNTER32, RONLY, isis_snmp_find_circ_counter},
+ {ISIS_CIRC_REJADJS, COUNTER32, RONLY, isis_snmp_find_circ_counter},
+ {ISIS_CIRC_IDFIELDLENMISMATCHES, COUNTER32, RONLY,
+ isis_snmp_find_circ_counter},
+ {ISIS_CIRC_MAXAREAADDRMISMATCHES, COUNTER32, RONLY,
+ isis_snmp_find_circ_counter},
+ {ISIS_CIRC_AUTHTYPEFAILS, COUNTER32, RONLY,
+ isis_snmp_find_circ_counter},
+ {ISIS_CIRC_AUTHFAILS, COUNTER32, RONLY, isis_snmp_find_circ_counter},
+ {ISIS_CIRC_LANDESISCHANGES, COUNTER32, RONLY,
+ isis_snmp_find_circ_counter},
+ {ISIS_ISADJ_STATE, INTEGER, RONLY, isis_snmp_find_isadj},
+ {ISIS_ISADJ_3WAYSTATE, INTEGER, RONLY, isis_snmp_find_isadj},
+ {ISIS_ISADJ_NEIGHSNPAADDRESS, STRING, RONLY, isis_snmp_find_isadj},
+ {ISIS_ISADJ_NEIGHSYSTYPE, INTEGER, RONLY, isis_snmp_find_isadj},
+ {ISIS_ISADJ_NEIGHSYSID, STRING, RONLY, isis_snmp_find_isadj},
+ {ISIS_ISADJ_NBREXTENDEDCIRCID, UNSIGNED32, RONLY, isis_snmp_find_isadj},
+ {ISIS_ISADJ_USAGE, INTEGER, RONLY, isis_snmp_find_isadj},
+ {ISIS_ISADJ_HOLDTIMER, UNSIGNED32, RONLY, isis_snmp_find_isadj},
+ {ISIS_ISADJ_NEIGHPRIORITY, UNSIGNED32, RONLY, isis_snmp_find_isadj},
+ {ISIS_ISADJ_LASTUPTIME, TIMESTAMP, RONLY, isis_snmp_find_isadj},
+ {ISIS_ISADJAREA_ADDRESS, STRING, RONLY, isis_snmp_find_isadj_area},
+ {ISIS_ISADJIPADDR_TYPE, INTEGER, RONLY, isis_snmp_find_isadj_ipaddr},
+ {ISIS_ISADJIPADDR_ADDRESS, STRING, RONLY, isis_snmp_find_isadj_ipaddr},
+ {ISIS_ISADJPROTSUPP_PROTOCOL, INTEGER, RONLY,
+ isis_snmp_find_isadj_prot_supp},
+};
+
+static const size_t isis_var_count = ARRAY_SIZE(isis_var_arr);
+
+/* Minimal set of hard-coded data */
+#define ISIS_VERSION (1)
+
+/* If sys-id is not set use this value */
+static uint8_t isis_null_sysid[ISIS_SYS_ID_LEN];
+
+/* OSI addr-len */
+#define ISIS_SNMP_OSI_ADDR_LEN_MAX (20)
+
+/*
+ * The implementation has a fixed max-path splits value
+ * of 64 (see ISIS_MAX_PATH_SPLITS), the max mib value
+ * is 32.
+ *
+ * FIXME(aromanov): should we return 32 or 64?
+ */
+#define ISIS_SNMP_MAX_PATH_SPLITS (32)
+
+#define ISIS_SNMP_ADMIN_STATE_ON (1)
+
+#define ISIS_SNMP_ROW_STATUS_ACTIVE (1)
+
+#define ISIS_SNMP_LEVEL_STATE_OFF (1)
+#define ISIS_SNMP_LEVEL_STATE_ON (2)
+#define ISIS_SNMP_LEVEL_STATE_WAITING (3)
+#define ISIS_SNMP_LEVEL_STATE_OVERLOADED (4)
+
+#define ISIS_SNMP_TRUTH_VALUE_TRUE (1)
+#define ISIS_SNMP_TRUTH_VALUE_FALSE (2)
+
+#define ISIS_SNMP_METRIC_STYLE_NARROW (1)
+#define ISIS_SNMP_METRIC_STYLE_WIDE (2)
+#define ISIS_SNMP_METRIC_STYLE_BOTH (3)
+
+#define ISIS_SNMP_MESH_GROUP_INACTIVE (1)
+
+#define ISIS_SNMP_ADJ_STATE_DOWN (1)
+#define ISIS_SNMP_ADJ_STATE_INITIALIZING (2)
+#define ISIS_SNMP_ADJ_STATE_UP (3)
+#define ISIS_SNMP_ADJ_STATE_FAILED (4)
+
+#define ISIS_SNMP_ADJ_NEIGHTYPE_IS_L1 (1)
+#define ISIS_SNMP_ADJ_NEIGHTYPE_IS_L2 (2)
+#define ISIS_SNMP_ADJ_NEIGHTYPE_IS_L1_L2 (3)
+#define ISIS_SNMP_ADJ_NEIGHTYPE_UNKNOWN (4)
+
+#define ISIS_SNMP_INET_TYPE_V4 (1)
+#define ISIS_SNMP_INET_TYPE_V6 (2)
+
+#define ISIS_SNMP_P2P_CIRCUIT (3)
+
+/* Protocols supported value */
+static uint8_t isis_snmp_protocols_supported = 0x7; /* All: iso, ipv4, ipv6 */
+
+/*
+ * Convenience function to move to the next circuit,
+ */
+static struct isis_circuit *isis_snmp_circuit_next(struct isis_circuit *circuit)
+{
+ uint32_t start;
+ uint32_t off;
+ struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+ if (isis == NULL)
+ return NULL;
+
+ start = 1;
+
+ if (circuit != NULL)
+ start = circuit->snmp_id + 1;
+
+ for (off = start; off < SNMP_CIRCUITS_MAX; off++) {
+ circuit = isis->snmp_circuits[off];
+
+ if (circuit != NULL)
+ return circuit;
+ }
+
+ return NULL;
+}
+
+/*
+ * Convenience function to get the first matching level
+ */
+static int isis_snmp_circuit_get_level_lo(struct isis_circuit *circuit)
+{
+ if (circuit->is_type == IS_LEVEL_2)
+ return IS_LEVEL_2;
+
+ return IS_LEVEL_1;
+}
+
+/* Check level match */
+static int isis_snmp_get_level_match(int is_type, int level)
+{
+ if (is_type != IS_LEVEL_1 && is_type != IS_LEVEL_2
+ && is_type != IS_LEVEL_1_AND_2)
+ return 0;
+
+ if (level != IS_LEVEL_1 && level != IS_LEVEL_2)
+ return 0;
+
+
+ if (is_type == IS_LEVEL_1) {
+ if (level == IS_LEVEL_1)
+ return 1;
+
+ return 0;
+ }
+
+ if (is_type == IS_LEVEL_2) {
+ if (level == IS_LEVEL_2)
+ return 1;
+
+ return 0;
+ }
+
+ return 1;
+}
+/*
+ * Helper function to convert oid index representing
+ * octet-string index (e.g. isis-sys-id) to byte string
+ * representing the same index.
+ *
+ * Also we do not fail if idx is longer than max_len,
+ * so we can use the same function to check compound
+ * indexes.
+ */
+static int isis_snmp_conv_exact(uint8_t *buf, size_t max_len, size_t *out_len,
+ const oid *idx, size_t idx_len)
+{
+ size_t off;
+ size_t len;
+
+ /* Oid representation: length followed by bytes */
+ if (idx == NULL || idx_len == 0)
+ return 0;
+
+ len = idx[0];
+
+ if (len > max_len)
+ return 0;
+
+ if (idx_len < len + 1)
+ return 0;
+
+ for (off = 0; off < len; off++) {
+ if (idx[off + 1] > 0xff)
+ return 0;
+
+ buf[off] = (uint8_t)(idx[off + 1] & 0xff);
+ }
+
+ *out_len = len;
+
+ return 1;
+}
+
+static int isis_snmp_conv_next(uint8_t *buf, size_t max_len, size_t *out_len,
+ int *try_exact, const oid *idx, size_t idx_len)
+{
+ size_t off;
+ size_t len;
+ size_t cmp_len;
+
+ if (idx == NULL || idx_len == 0) {
+ *out_len = 0;
+ *try_exact = 1;
+ return 1;
+ }
+
+ len = idx[0];
+
+ if (len > max_len)
+ return 0;
+
+ cmp_len = len;
+
+ if ((idx_len - 1) < cmp_len)
+ cmp_len = idx_len - 1;
+
+ for (off = 0; off < cmp_len; off++) {
+ if (idx[off + 1] > 0xff) {
+ memset(buf + off, 0xff, len - off);
+ *out_len = len;
+ *try_exact = 1;
+ return 1;
+ }
+
+ buf[off] = (uint8_t)(idx[off + 1] & 0xff);
+ }
+
+ if (cmp_len < len)
+ memset(buf + cmp_len, 0, len - cmp_len);
+
+ *out_len = len;
+ *try_exact = cmp_len < len ? 1 : 0;
+ return 1;
+}
+
+/*
+ * Helper functions to find area address from snmp index
+ */
+static int isis_snmp_area_addr_lookup_exact(oid *oid_idx, size_t oid_idx_len,
+ struct isis_area **ret_area,
+ struct area_addr **ret_addr)
+{
+ uint8_t cmp_buf[ISIS_SNMP_OSI_ADDR_LEN_MAX];
+ size_t addr_len;
+ struct isis_area *area = NULL;
+ struct area_addr *addr = NULL;
+ struct listnode *addr_node;
+ struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+ if (isis == NULL)
+ return 0;
+
+ if (list_isempty(isis->area_list)) {
+ /* Area is not configured yet */
+ return 0;
+ }
+
+ area = listgetdata(listhead(isis->area_list));
+
+ int res = isis_snmp_conv_exact(cmp_buf, sizeof(cmp_buf), &addr_len,
+ oid_idx, oid_idx_len);
+
+
+ if (!res || addr_len == 0 || oid_idx_len != (addr_len + 1)) {
+ /* Bad conversion, empty address or extra oids at the end */
+ return 0;
+ }
+
+ for (ALL_LIST_ELEMENTS_RO(area->area_addrs, addr_node, addr)) {
+ if (addr->addr_len != addr_len)
+ continue;
+
+ if (memcmp(addr->area_addr, cmp_buf, addr_len) == 0) {
+ if (ret_area != 0)
+ *ret_area = area;
+
+ if (ret_addr != 0)
+ *ret_addr = addr;
+
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int isis_snmp_area_addr_lookup_next(oid *oid_idx, size_t oid_idx_len,
+ struct isis_area **ret_area,
+ struct area_addr **ret_addr)
+{
+ uint8_t cmp_buf[ISIS_SNMP_OSI_ADDR_LEN_MAX];
+ size_t addr_len;
+ int try_exact = 0;
+ struct isis_area *found_area = NULL;
+ struct isis_area *area = NULL;
+ struct area_addr *found_addr = NULL;
+ struct area_addr *addr = NULL;
+ struct listnode *addr_node;
+ struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+ if (isis == NULL)
+ return 0;
+
+ if (list_isempty(isis->area_list)) {
+ /* Area is not configured yet */
+ return 0;
+ }
+
+ area = listgetdata(listhead(isis->area_list));
+
+ int res = isis_snmp_conv_next(cmp_buf, sizeof(cmp_buf), &addr_len,
+ &try_exact, oid_idx, oid_idx_len);
+
+ if (!res)
+ return 0;
+
+ for (ALL_LIST_ELEMENTS_RO(area->area_addrs, addr_node, addr)) {
+ if (addr->addr_len < addr_len)
+ continue;
+
+ if (addr->addr_len == addr_len) {
+ if (addr_len == 0)
+ continue;
+
+ res = memcmp(addr->area_addr, cmp_buf, addr_len);
+
+ if (res < 0)
+ continue;
+
+ if (res == 0 && addr->addr_len == addr_len) {
+ if (try_exact) {
+ /*
+ * This is the best match no point
+ * to look further
+ */
+ found_area = area;
+ found_addr = addr;
+ break;
+ }
+ continue;
+ }
+ }
+
+ if (found_addr == NULL || addr->addr_len < found_addr->addr_len
+ || (addr->addr_len == found_addr->addr_len
+ && memcmp(addr->area_addr, found_addr->area_addr,
+ addr->addr_len)
+ < 0)) {
+ found_area = area;
+ found_addr = addr;
+ }
+ }
+
+ if (found_area == NULL)
+ return 0;
+
+ if (ret_area != 0)
+ *ret_area = found_area;
+
+ if (ret_addr != 0)
+ *ret_addr = found_addr;
+
+ return 1;
+}
+
+/*
+ * Helper functions to find circuit from
+ * snmp index
+ */
+static int isis_snmp_circuit_lookup_exact(oid *oid_idx, size_t oid_idx_len,
+ struct isis_circuit **ret_circuit)
+{
+ struct isis_circuit *circuit;
+ struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+ if (isis == NULL)
+ return 0;
+
+ if (oid_idx == NULL || oid_idx_len < 1
+ || oid_idx[0] > SNMP_CIRCUITS_MAX)
+ return 0;
+
+ circuit = isis->snmp_circuits[oid_idx[0]];
+ if (circuit == NULL)
+ return 0;
+
+ if (ret_circuit != NULL)
+ *ret_circuit = circuit;
+
+ return 1;
+}
+
+static int isis_snmp_circuit_lookup_next(oid *oid_idx, size_t oid_idx_len,
+ struct isis_circuit **ret_circuit)
+{
+ oid off;
+ oid start;
+ struct isis_circuit *circuit;
+ struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+ if (isis == NULL)
+ return 0;
+
+ start = 0;
+
+ if (oid_idx != NULL || oid_idx_len != 0) {
+ if (oid_idx[0] > SNMP_CIRCUITS_MAX)
+ return 0;
+
+ start = oid_idx[0];
+ }
+
+ for (off = start; off < SNMP_CIRCUITS_MAX; ++off) {
+ circuit = isis->snmp_circuits[off];
+
+ if (circuit != NULL && off > start) {
+ if (ret_circuit != NULL)
+ *ret_circuit = circuit;
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Helper functions to find circuit level
+ * combination from snmp index
+ */
+static int isis_snmp_circuit_level_lookup_exact(
+ oid *oid_idx, size_t oid_idx_len, int check_match,
+ struct isis_circuit **ret_circuit, int *ret_level)
+{
+ int level;
+ int res;
+ struct isis_circuit *circuit;
+
+ /* Minor optimization: check level first */
+ if (oid_idx == NULL || oid_idx_len < 2)
+ return 0;
+
+ if (oid_idx[1] < IS_LEVEL_1 || oid_idx[1] > IS_LEVEL_2)
+ return 0;
+
+ level = (int)oid_idx[1];
+
+ res = isis_snmp_circuit_lookup_exact(oid_idx, oid_idx_len, &circuit);
+
+ if (!res)
+ return 0;
+
+ if (check_match && !isis_snmp_get_level_match(circuit->is_type, level))
+ return 0;
+
+ if (ret_circuit != NULL)
+ *ret_circuit = circuit;
+
+ if (ret_level != NULL)
+ *ret_level = level;
+
+ return 1;
+}
+
+static int isis_snmp_circuit_level_lookup_next(
+ oid *oid_idx, size_t oid_idx_len, int check_match,
+ struct isis_circuit **ret_circuit, int *ret_level)
+{
+ oid off;
+ oid start;
+ struct isis_circuit *circuit;
+ int level;
+ struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+ if (isis == NULL)
+ return 0;
+
+ start = 0;
+
+ if (oid_idx != NULL || oid_idx_len != 0) {
+ if (oid_idx[0] > SNMP_CIRCUITS_MAX)
+ return 0;
+
+ start = oid_idx[0];
+ }
+
+ for (off = start; off < SNMP_CIRCUITS_MAX; off++) {
+ circuit = isis->snmp_circuits[off];
+
+ if (circuit == NULL)
+ continue;
+
+ if (off > start || oid_idx_len < 2) {
+ /* Found and can use level 1 */
+ level = IS_LEVEL_1;
+ break;
+ }
+
+ /* We have to check level specified by index */
+ if (oid_idx[1] < IS_LEVEL_1) {
+ level = IS_LEVEL_1;
+ break;
+ }
+
+ if (oid_idx[1] < IS_LEVEL_2) {
+ level = IS_LEVEL_2;
+ break;
+ }
+
+ /* Try next */
+ circuit = NULL;
+ }
+
+ if (circuit == NULL)
+ return 0;
+
+ if (check_match
+ && !isis_snmp_get_level_match(circuit->is_type, level)) {
+ if (level == IS_LEVEL_1) {
+ /*
+ * We can simply advance level because
+ * at least one level should match
+ */
+ level = IS_LEVEL_2;
+ } else {
+ /* We have to move to the next circuit */
+ circuit = isis_snmp_circuit_next(circuit);
+ if (circuit == NULL)
+ return 0;
+
+ level = isis_snmp_circuit_get_level_lo(circuit);
+ }
+ }
+
+ if (ret_circuit != NULL)
+ *ret_circuit = circuit;
+
+ if (ret_level != NULL)
+ *ret_level = level;
+
+ return 1;
+}
+
+/*
+ * Helper functions to find adjacency
+ * from snmp index.
+ *
+ * We have 4 tables related to adjacency
+ * looking up adjacency is quite expensive
+ * in case of bcast interfaces.
+ *
+ * It is pain to have 4 very similar functions
+ * hence we pass in and out additional data
+ * we are looking for.
+ *
+ * Note: we use data-len value to distinguish
+ * between ipv4 and ipv6 addresses
+ */
+#define ISIS_SNMP_ADJ_DATA_NONE (1)
+#define ISIS_SNMP_ADJ_DATA_AREA_ADDR (2)
+#define ISIS_SNMP_ADJ_DATA_IP_ADDR (3)
+#define ISIS_SNMP_ADJ_DATA_PROTO (4)
+
+/*
+ * Helper function to process data associated
+ * with adjacency
+ */
+static int isis_snmp_adj_helper(struct isis_adjacency *adj, int data_id,
+ oid data_off, uint8_t **ret_data,
+ size_t *ret_data_len)
+{
+ uint8_t *data = NULL;
+ size_t data_len = 0;
+
+ switch (data_id) {
+ case ISIS_SNMP_ADJ_DATA_NONE:
+ break;
+
+ case ISIS_SNMP_ADJ_DATA_AREA_ADDR:
+ if (data_off >= adj->area_address_count)
+ return 0;
+
+ data = adj->area_addresses[data_off].area_addr;
+ data_len = adj->area_addresses[data_off].addr_len;
+ break;
+
+ case ISIS_SNMP_ADJ_DATA_IP_ADDR:
+ if (data_off
+ >= (adj->ipv4_address_count + adj->ipv6_address_count))
+ return 0;
+
+ if (data_off >= adj->ipv4_address_count) {
+ data = (uint8_t *)&adj->ipv6_addresses
+ [data_off - adj->ipv4_address_count];
+ data_len = sizeof(adj->ipv6_addresses[0]);
+ } else {
+ data = (uint8_t *)&adj->ipv4_addresses[data_off];
+ data_len = sizeof(adj->ipv4_addresses[0]);
+ }
+
+ break;
+
+
+ case ISIS_SNMP_ADJ_DATA_PROTO:
+ if (data_off >= adj->nlpids.count)
+ return 0;
+
+ data = &adj->nlpids.nlpids[data_off];
+ data_len = sizeof(adj->nlpids.nlpids[0]);
+ break;
+
+ default:
+ assert(0);
+ return 0;
+ }
+
+ if (ret_data != NULL)
+ *ret_data = data;
+
+ if (ret_data_len != NULL)
+ *ret_data_len = data_len;
+
+ return 1;
+}
+
+static int isis_snmp_adj_lookup_exact(oid *oid_idx, size_t oid_idx_len,
+ int data_id,
+ struct isis_adjacency **ret_adj,
+ oid *ret_data_idx, uint8_t **ret_data,
+ size_t *ret_data_len)
+{
+ int res;
+ struct listnode *node;
+ struct isis_circuit *circuit;
+ struct isis_adjacency *adj;
+ struct isis_adjacency *tmp_adj;
+ oid adj_idx;
+ oid data_off;
+ uint8_t *data;
+ size_t data_len;
+
+ res = isis_snmp_circuit_lookup_exact(oid_idx, oid_idx_len, &circuit);
+
+ if (!res)
+ return 0;
+
+ if (oid_idx == NULL || oid_idx_len < 2
+ || (data_id != ISIS_SNMP_ADJ_DATA_NONE && oid_idx_len < 3))
+ return 0;
+
+ adj_idx = oid_idx[1];
+
+ if (data_id != ISIS_SNMP_ADJ_DATA_NONE) {
+ if (oid_idx[2] == 0)
+ return 0;
+
+ data_off = oid_idx[2] - 1;
+ } else {
+ /*
+ * Data-off is not used if data-id is none
+ * but we set it just for consistency
+ */
+ data_off = 0;
+ }
+
+ adj = NULL;
+ data = NULL;
+ data_len = 0;
+
+ for (ALL_LIST_ELEMENTS_RO(circuit->snmp_adj_list, node, tmp_adj)) {
+ if (tmp_adj->snmp_idx > adj_idx) {
+ /*
+ * Adjacencies are ordered in the list
+ * no point to look further
+ */
+ break;
+ }
+
+ if (tmp_adj->snmp_idx == adj_idx) {
+ res = isis_snmp_adj_helper(tmp_adj, data_id, data_off,
+ &data, &data_len);
+ if (res)
+ adj = tmp_adj;
+
+ break;
+ }
+ }
+
+ if (adj == NULL)
+ return 0;
+
+ if (ret_adj != NULL)
+ *ret_adj = adj;
+
+ if (ret_data_idx != NULL)
+ *ret_data_idx = data_off + 1;
+
+ if (ret_data)
+ *ret_data = data;
+
+ if (ret_data_len)
+ *ret_data_len = data_len;
+
+ return 1;
+}
+
+static int isis_snmp_adj_lookup_next(oid *oid_idx, size_t oid_idx_len,
+ int data_id,
+ struct isis_adjacency **ret_adj,
+ oid *ret_data_idx, uint8_t **ret_data,
+ size_t *ret_data_len)
+{
+ struct listnode *node;
+ struct isis_circuit *circuit;
+ struct isis_adjacency *adj;
+ struct isis_adjacency *tmp_adj;
+ oid circ_idx;
+ oid adj_idx;
+ oid data_idx;
+ uint8_t *data;
+ size_t data_len;
+
+ adj = NULL;
+ data = NULL;
+ data_len = 0;
+
+ /*
+ * Note: we rely on the fact that data indexes are consequtive
+ * starting from 1
+ */
+
+ if (oid_idx == 0 || oid_idx_len == 0) {
+ circ_idx = 0;
+ adj_idx = 0;
+ data_idx = 0;
+ } else if (oid_idx_len == 1) {
+ circ_idx = oid_idx[0];
+ adj_idx = 0;
+ data_idx = 0;
+ } else if (oid_idx_len == 2) {
+ circ_idx = oid_idx[0];
+ adj_idx = oid_idx[1];
+ data_idx = 0;
+ } else {
+ circ_idx = oid_idx[0];
+ adj_idx = oid_idx[1];
+
+ if (data_id == ISIS_SNMP_ADJ_DATA_NONE)
+ data_idx = 0;
+ else
+ data_idx = oid_idx[2];
+ }
+
+ if (!isis_snmp_circuit_lookup_exact(&circ_idx, 1, &circuit)
+ && !isis_snmp_circuit_lookup_next(&circ_idx, 1, &circuit))
+ /* No circuit */
+ return 0;
+
+ if (circuit->snmp_id != circ_idx) {
+ /* Match is not exact */
+ circ_idx = 0;
+ adj_idx = 0;
+ data_idx = 0;
+ }
+
+ /*
+ * Note: the simple loop below will work in all cases
+ */
+ while (circuit != NULL) {
+ for (ALL_LIST_ELEMENTS_RO(circuit->snmp_adj_list, node,
+ tmp_adj)) {
+ if (tmp_adj->snmp_idx < adj_idx)
+ continue;
+
+ if (tmp_adj->snmp_idx == adj_idx
+ && data_id == ISIS_SNMP_ADJ_DATA_NONE)
+ continue;
+
+ if (adj_idx != 0 && tmp_adj->snmp_idx > adj_idx)
+ data_idx = 0;
+
+ if (isis_snmp_adj_helper(tmp_adj, data_id, data_idx,
+ &data, &data_len)) {
+ adj = tmp_adj;
+ break;
+ }
+ }
+
+ if (adj != NULL)
+ break;
+
+ circuit = isis_snmp_circuit_next(circuit);
+ circ_idx = 0;
+ adj_idx = 0;
+ data_idx = 0;
+ }
+
+ if (adj == NULL)
+ return 0;
+
+ if (ret_adj != NULL)
+ *ret_adj = adj;
+
+ if (ret_data_idx != 0) {
+ if (data_id == ISIS_SNMP_ADJ_DATA_NONE)
+ /*
+ * Value does not matter but let us set
+ * it to zero for consistency
+ */
+ *ret_data_idx = 0;
+ else
+ *ret_data_idx = data_idx + 1;
+ }
+
+ if (ret_data != 0)
+ *ret_data = data;
+
+ if (ret_data_len != 0)
+ *ret_data_len = data_len;
+
+ return 1;
+}
+
+static uint8_t *isis_snmp_find_sys_object(struct variable *v, oid *name,
+ size_t *length, int exact,
+ size_t *var_len,
+ WriteMethod **write_method)
+{
+ struct isis_area *area = NULL;
+ struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+ if (isis == NULL)
+ return NULL;
+
+ if (!list_isempty(isis->area_list))
+ area = listgetdata(listhead(isis->area_list));
+
+ /* Check whether the instance identifier is valid */
+ if (smux_header_generic(v, name, length, exact, var_len, write_method)
+ == MATCH_FAILED)
+ return NULL;
+
+ switch (v->magic) {
+ case ISIS_SYS_VERSION:
+ return SNMP_INTEGER(ISIS_VERSION);
+
+ case ISIS_SYS_LEVELTYPE:
+ /*
+ * If we do not have areas use 1&2 otherwise use settings
+ * from the first area in the list
+ */
+ if (area == NULL)
+ return SNMP_INTEGER(IS_LEVEL_1_AND_2);
+
+ return SNMP_INTEGER(area->is_type);
+
+ case ISIS_SYS_ID:
+ if (!isis->sysid_set) {
+ *var_len = ISIS_SYS_ID_LEN;
+ return isis_null_sysid;
+ }
+
+ *var_len = ISIS_SYS_ID_LEN;
+ return isis->sysid;
+
+ case ISIS_SYS_MAXPATHSPLITS:
+ return SNMP_INTEGER(ISIS_SNMP_MAX_PATH_SPLITS);
+
+ case ISIS_SYS_MAXLSPGENINT:
+ return SNMP_INTEGER(DEFAULT_MAX_LSP_GEN_INTERVAL);
+
+ case ISIS_SYS_POLLESHELLORATE:
+ return SNMP_INTEGER(DEFAULT_HELLO_INTERVAL);
+
+ case ISIS_SYS_WAITTIME:
+ /* Note: it seems that we have same fixed delay time */
+ return SNMP_INTEGER(DEFAULT_MIN_LSP_GEN_INTERVAL);
+
+ case ISIS_SYS_ADMINSTATE:
+ /* If daemon is running it admin state is on */
+ return SNMP_INTEGER(ISIS_SNMP_ADMIN_STATE_ON);
+
+
+ case ISIS_SYS_L2TOL1LEAKING:
+ /* We do not allow l2-to-l1 leaking */
+ return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE);
+
+ case ISIS_SYS_MAXAGE:
+ return SNMP_INTEGER(MAX_AGE);
+
+ case ISIS_SYS_RECEIVELSPBUFFERSIZE:
+ if (area == NULL)
+ return SNMP_INTEGER(DEFAULT_LSP_MTU);
+
+ return SNMP_INTEGER(area->lsp_mtu);
+
+ case ISIS_SYS_PROTSUPPORTED:
+ *var_len = 1;
+ return &isis_snmp_protocols_supported;
+
+ case ISIS_SYS_NOTIFICATIONENABLE:
+ if (isis->snmp_notifications)
+ return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_TRUE);
+
+ return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE);
+
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+
+static uint8_t *isis_snmp_find_man_area(struct variable *v, oid *name,
+ size_t *length, int exact,
+ size_t *var_len,
+ WriteMethod **write_method)
+{
+ int res;
+ struct area_addr *area_addr = NULL;
+ oid *oid_idx;
+ size_t oid_idx_len;
+ size_t off = 0;
+
+ *write_method = NULL;
+
+ if (*length <= v->namelen) {
+ oid_idx = NULL;
+ oid_idx_len = 0;
+ } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
+ oid_idx = NULL;
+ oid_idx_len = 0;
+ } else {
+ oid_idx = name + v->namelen;
+ oid_idx_len = *length - v->namelen;
+ }
+
+ if (exact) {
+ res = isis_snmp_area_addr_lookup_exact(oid_idx, oid_idx_len,
+ NULL, &area_addr);
+
+ if (!res)
+ return NULL;
+
+ } else {
+ res = isis_snmp_area_addr_lookup_next(oid_idx, oid_idx_len,
+ NULL, &area_addr);
+
+ if (!res)
+ return NULL;
+
+ /* Copy the name out */
+ memcpy(name, v->name, v->namelen * sizeof(oid));
+
+ /* Append index */
+ name[v->namelen] = area_addr->addr_len;
+
+ for (off = 0; off < area_addr->addr_len; off++)
+ name[v->namelen + 1 + off] = area_addr->area_addr[off];
+
+ *length = v->namelen + 1 + area_addr->addr_len;
+ }
+
+ switch (v->magic) {
+ case ISIS_MANAREA_ADDREXISTSTATE:
+ return SNMP_INTEGER(ISIS_SNMP_ROW_STATUS_ACTIVE);
+
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+static uint8_t *isis_snmp_find_area_addr(struct variable *v, oid *name,
+ size_t *length, int exact,
+ size_t *var_len,
+ WriteMethod **write_method)
+{
+ /*
+ * Area addresses in sense of addresses reported by L1 lsps
+ * are not supported yet.
+ */
+ (void)v;
+ (void)name;
+ (void)length;
+ (void)exact;
+ (void)var_len;
+
+
+ *write_method = NULL;
+
+ return NULL;
+}
+
+static uint8_t *isis_snmp_find_summ_addr(struct variable *v, oid *name,
+ size_t *length, int exact,
+ size_t *var_len,
+ WriteMethod **write_method)
+{
+ /*
+ * So far there is no way to set summary table values through cli
+ * and snmp operations are read-only, hence there are no entries
+ */
+ (void)v;
+ (void)name;
+ (void)length;
+ (void)exact;
+ (void)var_len;
+ *write_method = NULL;
+
+ return NULL;
+}
+
+static uint8_t *isis_snmp_find_redistribute_addr(struct variable *v, oid *name,
+ size_t *length, int exact,
+ size_t *var_len,
+ WriteMethod **write_method)
+{
+ /*
+ * It is not clear at the point whether redist code in isis is actually
+ * used for now we will consider that entries are not present
+ */
+ (void)v;
+ (void)name;
+ (void)length;
+ (void)exact;
+ (void)var_len;
+ *write_method = NULL;
+
+ return NULL;
+}
+
+static uint8_t *isis_snmp_find_router(struct variable *v, oid *name,
+ size_t *length, int exact,
+ size_t *var_len,
+ WriteMethod **write_method)
+{
+ uint8_t cmp_buf[ISIS_SYS_ID_LEN];
+ size_t cmp_len;
+ int try_exact;
+ int cmp_level;
+ int res;
+ struct isis_dynhn *dyn = NULL;
+ oid *oid_idx;
+ size_t oid_idx_len;
+ size_t off = 0;
+
+ *write_method = NULL;
+
+ if (*length <= v->namelen) {
+ oid_idx = NULL;
+ oid_idx_len = 0;
+ } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
+ oid_idx = NULL;
+ oid_idx_len = 0;
+ } else {
+ oid_idx = name + v->namelen;
+ oid_idx_len = *length - v->namelen;
+ }
+
+ if (exact) {
+ res = isis_snmp_conv_exact(cmp_buf, sizeof(cmp_buf), &cmp_len,
+ oid_idx, oid_idx_len);
+
+ if (!res || cmp_len != ISIS_SYS_ID_LEN
+ || oid_idx_len != (cmp_len + 2))
+ /*
+ * Bad conversion, or bad length,
+ * or extra oids at the end
+ */
+ return NULL;
+
+ if (oid_idx[ISIS_SYS_ID_LEN + 1] < IS_LEVEL_1
+ || oid_idx[ISIS_SYS_ID_LEN + 1] > IS_LEVEL_2)
+ /* Level part of the index is out of range */
+ return NULL;
+
+ cmp_level = (int)oid_idx[ISIS_SYS_ID_LEN + 1];
+
+ dyn = dynhn_find_by_id(cmp_buf);
+
+ if (dyn == NULL || dyn->level != cmp_level)
+ return NULL;
+
+ switch (v->magic) {
+ case ISIS_ROUTER_HOSTNAME:
+ *var_len = strlen(dyn->hostname);
+ return (uint8_t *)dyn->hostname;
+
+ case ISIS_ROUTER_ID:
+ /* It seems that we do no know router-id in lsps */
+ return SNMP_INTEGER(0);
+
+ default:
+ break;
+ }
+
+ return NULL;
+ }
+
+ res = isis_snmp_conv_next(cmp_buf, sizeof(cmp_buf), &cmp_len,
+ &try_exact, oid_idx, oid_idx_len);
+
+
+ if (!res)
+ /* Bad conversion */
+ return NULL;
+
+ if (cmp_len != ISIS_SYS_ID_LEN) {
+ /* We do not have valid index oids */
+ memset(cmp_buf, 0, sizeof(cmp_buf));
+ cmp_level = 0;
+ } else if (try_exact)
+ /*
+ * We have no valid level index.
+ * Let start from non-existing level 0 and
+ * hence not need to do exact match
+ */
+ cmp_level = 0;
+ else if (oid_idx_len < (ISIS_SYS_ID_LEN + 2))
+ cmp_level = 0;
+ else if (oid_idx[ISIS_SYS_ID_LEN + 1] <= IS_LEVEL_2)
+ cmp_level = (int)oid_idx[ISIS_SYS_ID_LEN + 1];
+ else
+ /*
+ * Any value greater than 2 will have the same result
+ * but we can have integer overflows, hence 3 is a reasonable
+ * choice
+ */
+ cmp_level = (int)(IS_LEVEL_2 + 1);
+
+ dyn = dynhn_snmp_next(cmp_buf, cmp_level);
+
+ if (dyn == NULL)
+ return NULL;
+
+ /* Copy the name out */
+ memcpy(name, v->name, v->namelen * sizeof(oid));
+
+ /* Append index */
+ name[v->namelen] = ISIS_SYS_ID_LEN;
+
+ for (off = 0; off < ISIS_SYS_ID_LEN; off++)
+ name[v->namelen + 1 + off] = dyn->id[off];
+
+ name[v->namelen + 1 + ISIS_SYS_ID_LEN] = (oid)dyn->level;
+
+ /* Set length */
+ *length = v->namelen + 1 + ISIS_SYS_ID_LEN + 1;
+
+ switch (v->magic) {
+ case ISIS_ROUTER_HOSTNAME:
+ *var_len = strlen(dyn->hostname);
+ return (uint8_t *)dyn->hostname;
+
+ case ISIS_ROUTER_ID:
+ /* It seems that we do no know router-id in lsps */
+ return SNMP_INTEGER(0);
+
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+static uint8_t *isis_snmp_find_sys_level(struct variable *v, oid *name,
+ size_t *length, int exact,
+ size_t *var_len,
+ WriteMethod **write_method)
+{
+ oid *oid_idx;
+ size_t oid_idx_len;
+ int level;
+ int level_match;
+ struct isis_area *area = NULL;
+ struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+ if (isis == NULL)
+ return NULL;
+
+ *write_method = NULL;
+
+ if (*length <= v->namelen) {
+ oid_idx = NULL;
+ oid_idx_len = 0;
+ } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
+ oid_idx = NULL;
+ oid_idx_len = 0;
+ } else {
+ oid_idx = name + v->namelen;
+ oid_idx_len = *length - v->namelen;
+ }
+
+ if (exact) {
+ if (oid_idx == NULL || oid_idx_len != 1)
+ return NULL;
+
+ if (oid_idx[0] == IS_LEVEL_1)
+ level = IS_LEVEL_1;
+ else if (oid_idx[0] == IS_LEVEL_2)
+ level = IS_LEVEL_2;
+ else
+ return NULL;
+
+ } else {
+ if (oid_idx == NULL)
+ level = IS_LEVEL_1;
+ else if (oid_idx_len == 0)
+ level = IS_LEVEL_1;
+ else if (oid_idx[0] < IS_LEVEL_1)
+ level = IS_LEVEL_1;
+ else if (oid_idx[0] < IS_LEVEL_2)
+ level = IS_LEVEL_2;
+ else
+ return NULL;
+
+ /* Copy the name out */
+ memcpy(name, v->name, v->namelen * sizeof(oid));
+
+ /* Append index */
+ name[v->namelen] = level;
+
+ /* Set length */
+ *length = v->namelen + 1;
+ }
+
+ area = NULL;
+
+ if (!list_isempty(isis->area_list))
+ area = listgetdata(listhead(isis->area_list));
+
+ level_match = 0;
+
+ if (area != NULL)
+ level_match = isis_snmp_get_level_match(area->is_type, level);
+
+ switch (v->magic) {
+ case ISIS_SYSLEVEL_ORIGLSPBUFFSIZE:
+ if (level_match)
+ return SNMP_INTEGER(area->lsp_mtu);
+
+ return SNMP_INTEGER(DEFAULT_LSP_MTU);
+
+ case ISIS_SYSLEVEL_MINLSPGENINT:
+ if (level_match)
+ return SNMP_INTEGER(area->lsp_gen_interval[level - 1]);
+ else
+ return SNMP_INTEGER(DEFAULT_MIN_LSP_GEN_INTERVAL);
+
+ case ISIS_SYSLEVEL_STATE:
+ if (level_match) {
+ if (area->overload_bit)
+ return SNMP_INTEGER(
+ ISIS_SNMP_LEVEL_STATE_OVERLOADED);
+
+ return SNMP_INTEGER(ISIS_SNMP_LEVEL_STATE_ON);
+ }
+ return SNMP_INTEGER(ISIS_SNMP_LEVEL_STATE_OFF);
+
+ case ISIS_SYSLEVEL_SETOVERLOAD:
+ if (level_match && area->overload_bit)
+ return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_TRUE);
+
+ return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE);
+
+ case ISIS_SYSLEVEL_SETOVERLOADUNTIL:
+ /* We do not have automatic cleanup of overload bit */
+ return SNMP_INTEGER(0);
+
+ case ISIS_SYSLEVEL_METRICSTYLE:
+ if (level_match) {
+ if (area->newmetric && area->oldmetric)
+ return SNMP_INTEGER(
+ ISIS_SNMP_METRIC_STYLE_BOTH);
+
+ if (area->newmetric)
+ return SNMP_INTEGER(
+ ISIS_SNMP_METRIC_STYLE_WIDE);
+
+ return SNMP_INTEGER(ISIS_SNMP_METRIC_STYLE_NARROW);
+ }
+ return SNMP_INTEGER(ISIS_SNMP_METRIC_STYLE_NARROW);
+
+ case ISIS_SYSLEVEL_SPFCONSIDERS:
+ return SNMP_INTEGER(ISIS_SNMP_METRIC_STYLE_BOTH);
+
+ case ISIS_SYSLEVEL_TEENABLED:
+ if (level_match && IS_MPLS_TE(area->mta))
+ return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_TRUE);
+
+ return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE);
+
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+static uint8_t *isis_snmp_find_system_counter(struct variable *v, oid *name,
+ size_t *length, int exact,
+ size_t *var_len,
+ WriteMethod **write_method)
+{
+ oid *oid_idx;
+ size_t oid_idx_len;
+ int level;
+ int level_match;
+ struct isis_area *area = NULL;
+ uint32_t val;
+ struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+ if (isis == NULL)
+ return NULL;
+
+ *write_method = NULL;
+
+ if (*length <= v->namelen) {
+ oid_idx = NULL;
+ oid_idx_len = 0;
+ } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
+ oid_idx = NULL;
+ oid_idx_len = 0;
+ } else {
+ oid_idx = name + v->namelen;
+ oid_idx_len = *length - v->namelen;
+ }
+
+ if (exact) {
+ if (oid_idx == NULL || oid_idx_len != 1)
+ return 0;
+
+ if (oid_idx[0] == IS_LEVEL_1)
+ level = IS_LEVEL_1;
+ else if (oid_idx[0] == IS_LEVEL_2)
+ level = IS_LEVEL_2;
+ else
+ return NULL;
+
+ } else {
+ if (oid_idx == NULL)
+ level = IS_LEVEL_1;
+ else if (oid_idx_len == 0)
+ level = IS_LEVEL_1;
+ else if (oid_idx[0] < IS_LEVEL_1)
+ level = IS_LEVEL_1;
+ else if (oid_idx[0] < IS_LEVEL_2)
+ level = IS_LEVEL_2;
+ else
+ return NULL;
+
+ /* Copy the name out */
+ memcpy(name, v->name, v->namelen * sizeof(oid));
+
+ /* Append index */
+ name[v->namelen] = level;
+
+ /* Set length */
+ *length = v->namelen + 1;
+ }
+
+ area = NULL;
+
+ if (!list_isempty(isis->area_list))
+ area = listgetdata(listhead(isis->area_list));
+
+ level_match = 0;
+
+ if (area != NULL)
+ level_match = isis_snmp_get_level_match(area->is_type, level);
+
+ if (!level_match)
+ /* If level does not match all counters are zeros */
+ return SNMP_INTEGER(0);
+
+ val = 0;
+
+ switch (v->magic) {
+ case ISIS_SYSSTAT_CORRLSPS:
+ val = 0;
+ break;
+
+ case ISIS_SYSSTAT_AUTHTYPEFAILS:
+ val = (uint32_t)area->auth_type_failures[level - 1];
+ break;
+
+ case ISIS_SYSSTAT_AUTHFAILS:
+ val = (uint32_t)area->auth_failures[level - 1];
+ break;
+
+ case ISIS_SYSSTAT_LSPDBASEOLOADS:
+ val = area->overload_counter;
+ break;
+
+ case ISIS_SYSSTAT_MANADDRDROPFROMAREAS:
+ /* We do not support manual addresses */
+ val = 0;
+ break;
+
+ case ISIS_SYSSTAT_ATTMPTTOEXMAXSEQNUMS:
+ val = area->lsp_exceeded_max_counter;
+ break;
+
+ case ISIS_SYSSTAT_SEQNUMSKIPS:
+ val = area->lsp_seqno_skipped_counter;
+ break;
+
+ case ISIS_SYSSTAT_OWNLSPPURGES:
+ if (!area->purge_originator)
+ val = 0;
+ else
+ val = area->lsp_purge_count[level - 1];
+ break;
+
+ case ISIS_SYSSTAT_IDFIELDLENMISMATCHES:
+ val = (uint32_t)area->id_len_mismatches[level - 1];
+ break;
+
+ case ISIS_SYSSTAT_PARTCHANGES:
+ /* Not supported */
+ val = 0;
+ break;
+
+ case ISIS_SYSSTAT_SPFRUNS:
+ val = (uint32_t)area->spf_run_count[level - 1];
+ break;
+
+ case ISIS_SYSSTAT_LSPERRORS:
+ val = (uint32_t)area->lsp_error_counter[level - 1];
+ break;
+
+ default:
+ return NULL;
+ }
+
+ return SNMP_INTEGER(val);
+}
+
+static uint8_t *isis_snmp_find_next_circ_index(struct variable *v, oid *name,
+ size_t *length, int exact,
+ size_t *var_len,
+ WriteMethod **write_method)
+{
+ /* Check whether the instance identifier is valid */
+ if (smux_header_generic(v, name, length, exact, var_len, write_method)
+ == MATCH_FAILED)
+ return NULL;
+
+ switch (v->magic) {
+ case ISIS_NEXTCIRC_INDEX:
+ /*
+ * We do not support circuit creation through snmp
+ */
+ return SNMP_INTEGER(0);
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static uint8_t *isis_snmp_find_circ(struct variable *v, oid *name,
+ size_t *length, int exact, size_t *var_len,
+ WriteMethod **write_method)
+{
+ /* Index is circuit-id: 1-255 */
+ oid *oid_idx;
+ size_t oid_idx_len;
+ struct isis_circuit *circuit;
+ uint64_t up_ticks;
+ uint64_t delta_ticks;
+ uint32_t now_time;
+ int res;
+
+ *write_method = NULL;
+
+ if (*length <= v->namelen) {
+ oid_idx = NULL;
+ oid_idx_len = 0;
+ } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
+ oid_idx = NULL;
+ oid_idx_len = 0;
+ } else {
+ oid_idx = name + v->namelen;
+ oid_idx_len = *length - v->namelen;
+ }
+ if (exact) {
+ res = isis_snmp_circuit_lookup_exact(oid_idx, oid_idx_len,
+ &circuit);
+
+ if (!res || oid_idx_len != 1)
+ return NULL;
+
+ } else {
+ res = isis_snmp_circuit_lookup_next(oid_idx, oid_idx_len,
+ &circuit);
+
+ if (!res)
+ return NULL;
+
+ /* Copy the name out */
+ memcpy(name, v->name, v->namelen * sizeof(oid));
+
+ /* Append index */
+ name[v->namelen] = circuit->snmp_id;
+
+ /* Set length */
+ *length = v->namelen + 1;
+ }
+
+ switch (v->magic) {
+ case ISIS_CIRC_IFINDEX:
+ if (circuit->interface == 0)
+ return SNMP_INTEGER(0);
+
+ return SNMP_INTEGER(circuit->interface->ifindex);
+
+ case ISIS_CIRC_ADMINSTATE:
+ return SNMP_INTEGER(ISIS_SNMP_ADMIN_STATE_ON);
+
+ case ISIS_CIRC_EXISTSTATE:
+ return SNMP_INTEGER(ISIS_SNMP_ROW_STATUS_ACTIVE);
+
+ case ISIS_CIRC_TYPE:
+ /*
+ * Note: values do not match 100%:
+ *
+ * 1. From isis_circuit.h:
+ * CIRCUIT_T_UNKNOWN 0
+ * CIRCUIT_T_BROADCAST 1
+ * CIRCUIT_T_P2P 2
+ * CIRCUIT_T_LOOPBACK 3
+ *
+ * 2. From rfc:
+ * broadcast(1),
+ * ptToPt(2),
+ * staticIn(3),
+ * staticOut(4),
+ */
+
+ return SNMP_INTEGER(circuit->circ_type);
+
+ case ISIS_CIRC_EXTDOMAIN:
+ if (circuit->ext_domain)
+ return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_TRUE);
+
+ return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE);
+
+ case ISIS_CIRC_LEVELTYPE:
+ return SNMP_INTEGER(circuit->is_type);
+
+ case ISIS_CIRC_PASSIVECIRCUIT:
+ if (circuit->is_passive)
+ return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_TRUE);
+
+ return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE);
+
+ case ISIS_CIRC_MESHGROUPENABLED:
+ /* Not supported */
+ return SNMP_INTEGER(ISIS_SNMP_MESH_GROUP_INACTIVE);
+
+ case ISIS_CIRC_MESHGROUP:
+ /* Not supported */
+ return SNMP_INTEGER(0);
+
+ case ISIS_CIRC_SMALLHELLOS:
+ /*
+ * return false if lan hellos must be padded
+ */
+ if (circuit->pad_hellos)
+ return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE);
+
+ return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_TRUE);
+
+ case ISIS_CIRC_LASTUPTIME:
+ if (circuit->last_uptime == 0)
+ return SNMP_INTEGER(0);
+
+ up_ticks = netsnmp_get_agent_uptime();
+ now_time = isis_snmp_time();
+
+ if (circuit->last_uptime >= now_time)
+ return SNMP_INTEGER(up_ticks);
+
+ delta_ticks = (now_time - circuit->last_uptime) * 10;
+
+ if (up_ticks < delta_ticks)
+ return SNMP_INTEGER(up_ticks);
+
+ return SNMP_INTEGER((uint32_t)(up_ticks - delta_ticks));
+
+ case ISIS_CIRC_3WAYENABLED:
+ /* Not supported */
+ return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE);
+
+ case ISIS_CIRC_EXTENDEDCIRCID:
+ /* Used for 3-way hand shake only */
+ return SNMP_INTEGER(0);
+
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+static uint8_t *isis_snmp_find_circ_level(struct variable *v, oid *name,
+ size_t *length, int exact,
+ size_t *var_len,
+ WriteMethod **write_method)
+{
+ static uint8_t circuit_id_val[ISIS_SYS_ID_LEN + 1];
+ /* Index is circuit-id: 1-255 + level: 1-2 */
+ oid *oid_idx;
+ size_t oid_idx_len;
+ int res;
+ struct isis_circuit *circuit;
+ int level;
+ struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+ if (isis == NULL)
+ return NULL;
+
+ *write_method = NULL;
+
+ if (*length <= v->namelen) {
+ oid_idx = NULL;
+ oid_idx_len = 0;
+ } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
+ oid_idx = NULL;
+ oid_idx_len = 0;
+ } else {
+ oid_idx = name + v->namelen;
+ oid_idx_len = *length - v->namelen;
+ }
+ if (exact) {
+ res = isis_snmp_circuit_level_lookup_exact(oid_idx, oid_idx_len,
+ 1, &circuit, &level);
+
+ if (!res || oid_idx_len != 2)
+ return NULL;
+
+ } else {
+ res = isis_snmp_circuit_level_lookup_next(oid_idx, oid_idx_len,
+ 1, &circuit, &level);
+
+ if (!res)
+ return NULL;
+
+ /* Copy the name out */
+ memcpy(name, v->name, v->namelen * sizeof(oid));
+
+ /* Append index */
+ name[v->namelen] = circuit->snmp_id;
+ name[v->namelen + 1] = level;
+
+ /* Set length */
+ *length = v->namelen + 2;
+ }
+
+ switch (v->magic) {
+ case ISIS_CIRCLEVEL_METRIC:
+ return SNMP_INTEGER(circuit->metric[level - 1]);
+
+ case ISIS_CIRCLEVEL_WIDEMETRIC:
+ if (circuit->area == NULL || !circuit->area->newmetric) {
+ /* What should we do if wide metric is not supported? */
+ return SNMP_INTEGER(0);
+ }
+ return SNMP_INTEGER(circuit->te_metric[level - 1]);
+
+ case ISIS_CIRCLEVEL_ISPRIORITY:
+ return SNMP_INTEGER(circuit->priority[level - 1]);
+
+ case ISIS_CIRCLEVEL_IDOCTET:
+ return SNMP_INTEGER(circuit->circuit_id);
+
+ case ISIS_CIRCLEVEL_ID:
+ if (circuit->circ_type != CIRCUIT_T_P2P) {
+ /*
+ * Unless it is point-to-point circuit, the value is and
+ * empty octet string
+ */
+ *var_len = 0;
+ return circuit_id_val;
+ }
+
+ /* !!!!!! Circuit-id is zero for p2p links */
+ if (circuit->u.p2p.neighbor == NULL
+ || circuit->u.p2p.neighbor->adj_state != ISIS_ADJ_UP) {
+ /* No adjacency or adjacency not fully up yet */
+ memcpy(circuit_id_val, isis->sysid, ISIS_SYS_ID_LEN);
+ circuit_id_val[ISIS_SYS_ID_LEN] = circuit->circuit_id;
+ *var_len = ISIS_SYS_ID_LEN + 1;
+ return circuit_id_val;
+ }
+
+ /* Adjacency fully-up */
+ memcpy(circuit_id_val, circuit->u.p2p.neighbor->sysid,
+ ISIS_SYS_ID_LEN);
+ circuit_id_val[ISIS_SYS_ID_LEN] = 0;
+ *var_len = ISIS_SYS_ID_LEN + 1;
+ return circuit_id_val;
+
+ case ISIS_CIRCLEVEL_DESIS:
+ if (circuit->circ_type != CIRCUIT_T_BROADCAST
+ || !circuit->u.bc.is_dr[level - 1]) {
+ /*
+ * Unless it is lan circuit participating in dis process
+ * the value is an empty octet string
+ */
+ *var_len = 0;
+ return circuit_id_val;
+ }
+
+ *var_len = ISIS_SYS_ID_LEN + 1;
+
+ if (level == IS_LEVEL_1)
+ return circuit->u.bc.l1_desig_is;
+
+ return circuit->u.bc.l2_desig_is;
+
+ case ISIS_CIRCLEVEL_HELLOMULTIPLIER:
+ return SNMP_INTEGER(circuit->hello_multiplier[level - 1]);
+
+ case ISIS_CIRCLEVEL_HELLOTIMER:
+ return SNMP_INTEGER(circuit->hello_interval[level - 1] * 1000);
+
+ case ISIS_CIRCLEVEL_DRHELLOTIMER:
+ return SNMP_INTEGER(circuit->hello_interval[level - 1] * 1000);
+
+ case ISIS_CIRCLEVEL_LSPTHROTTLE:
+ if (circuit->area)
+ return SNMP_INTEGER(
+ circuit->area->min_spf_interval[level - 1]
+ * 1000);
+ else
+ return SNMP_INTEGER(0);
+
+ case ISIS_CIRCLEVEL_MINLSPRETRANSINT:
+ if (circuit->area)
+ return SNMP_INTEGER(
+ circuit->area->min_spf_interval[level - 1]);
+ else
+ return SNMP_INTEGER(0);
+
+ case ISIS_CIRCLEVEL_CSNPINTERVAL:
+ return SNMP_INTEGER(circuit->csnp_interval[level - 1]);
+
+ case ISIS_CIRCLEVEL_PARTSNPINTERVAL:
+ return SNMP_INTEGER(circuit->psnp_interval[level - 1]);
+
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+static uint8_t *isis_snmp_find_circ_counter(struct variable *v, oid *name,
+ size_t *length, int exact,
+ size_t *var_len,
+ WriteMethod **write_method)
+{
+ /* Index circuit-id 1-255 + level */
+ oid *oid_idx;
+ size_t oid_idx_len;
+ int res;
+ struct isis_circuit *circuit;
+ int level;
+ uint32_t val = 0;
+
+ *write_method = NULL;
+
+ if (*length <= v->namelen) {
+ oid_idx = NULL;
+ oid_idx_len = 0;
+ } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
+ oid_idx = NULL;
+ oid_idx_len = 0;
+ } else {
+ oid_idx = name + v->namelen;
+ oid_idx_len = *length - v->namelen;
+ }
+ if (exact) {
+ res = isis_snmp_circuit_level_lookup_exact(oid_idx, oid_idx_len,
+ 1, &circuit, &level);
+
+ if (!res || oid_idx_len != 2)
+ return NULL;
+
+ } else {
+ res = isis_snmp_circuit_level_lookup_next(oid_idx, oid_idx_len,
+ 1, &circuit, &level);
+
+ if (!res)
+ return NULL;
+
+ /* Copy the name out */
+ memcpy(name, v->name, v->namelen * sizeof(oid));
+
+ /* Append index */
+ name[v->namelen] = circuit->snmp_id;
+ if (circuit->circ_type == CIRCUIT_T_P2P)
+ name[v->namelen + 1] = ISIS_SNMP_P2P_CIRCUIT;
+ else
+ name[v->namelen + 1] = level;
+
+ /* Set length */
+ *length = v->namelen + 2;
+ }
+
+ switch (v->magic) {
+ case ISIS_CIRC_ADJCHANGES:
+ val = circuit->adj_state_changes;
+ break;
+
+ case ISIS_CIRC_NUMADJ:
+ if (circuit->circ_type == CIRCUIT_T_P2P) {
+ val = circuit->u.p2p.neighbor == NULL ? 0 : 1;
+ break;
+ }
+
+ if (circuit->circ_type != CIRCUIT_T_BROADCAST) {
+ val = 0;
+ break;
+ }
+
+ if (level == IS_LEVEL_1) {
+ if (circuit->u.bc.adjdb[0] == NULL)
+ val = 0;
+ else
+ val = listcount(circuit->u.bc.adjdb[0]);
+ break;
+ }
+
+ if (circuit->u.bc.adjdb[1] == NULL)
+ val = 0;
+ else
+ val = listcount(circuit->u.bc.adjdb[1]);
+
+ break;
+
+ case ISIS_CIRC_INITFAILS:
+ val = circuit->init_failures; /* counter never incremented */
+ break;
+
+ case ISIS_CIRC_REJADJS:
+ val = circuit->rej_adjacencies;
+ break;
+
+ case ISIS_CIRC_IDFIELDLENMISMATCHES:
+ val = circuit->id_len_mismatches;
+ break;
+
+ case ISIS_CIRC_MAXAREAADDRMISMATCHES:
+ val = circuit->max_area_addr_mismatches;
+ break;
+
+ case ISIS_CIRC_AUTHTYPEFAILS:
+ val = circuit->auth_type_failures;
+ break;
+
+ case ISIS_CIRC_AUTHFAILS:
+ val = circuit->auth_failures;
+ break;
+
+ case ISIS_CIRC_LANDESISCHANGES:
+ if (circuit->circ_type == CIRCUIT_T_P2P)
+ val = 0;
+ else
+ val = circuit->desig_changes[level - 1];
+ break;
+
+ default:
+ return NULL;
+ }
+
+ return SNMP_INTEGER(val);
+}
+
+static uint8_t *isis_snmp_find_isadj(struct variable *v, oid *name,
+ size_t *length, int exact, size_t *var_len,
+ WriteMethod **write_method)
+{
+ /* Index is circuit-id: 1-255 + adj-id: 1-... */
+ oid *oid_idx;
+ size_t oid_idx_len;
+ int res;
+ uint32_t val;
+ struct isis_adjacency *adj;
+ uint64_t up_ticks;
+ uint64_t delta_ticks;
+ uint32_t now_time;
+
+ *write_method = NULL;
+
+ if (*length <= v->namelen) {
+ oid_idx = NULL;
+ oid_idx_len = 0;
+ } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
+ oid_idx = NULL;
+ oid_idx_len = 0;
+ } else {
+ oid_idx = name + v->namelen;
+ oid_idx_len = *length - v->namelen;
+ }
+ if (exact) {
+ res = isis_snmp_adj_lookup_exact(oid_idx, oid_idx_len,
+ ISIS_SNMP_ADJ_DATA_NONE, &adj,
+ NULL, NULL, NULL);
+
+ if (!res || oid_idx_len != 2)
+ return NULL;
+
+ } else {
+ res = isis_snmp_adj_lookup_next(oid_idx, oid_idx_len,
+ ISIS_SNMP_ADJ_DATA_NONE, &adj,
+ NULL, NULL, NULL);
+ if (!res)
+ return NULL;
+
+ /* Copy the name out */
+ memcpy(name, v->name, v->namelen * sizeof(oid));
+
+ /* Append index */
+ name[v->namelen] = adj->circuit->snmp_id;
+ name[v->namelen + 1] = adj->snmp_idx;
+
+ /* Set length */
+ *length = v->namelen + 2;
+ }
+
+ switch (v->magic) {
+ case ISIS_ISADJ_STATE:
+ val = ISIS_SNMP_ADJ_STATE_DOWN;
+
+ switch (adj->adj_state) {
+ case ISIS_ADJ_UNKNOWN:
+ case ISIS_ADJ_DOWN:
+ val = ISIS_SNMP_ADJ_STATE_DOWN;
+ break;
+
+ case ISIS_ADJ_INITIALIZING:
+ val = ISIS_SNMP_ADJ_STATE_INITIALIZING;
+ break;
+
+ case ISIS_ADJ_UP:
+ val = ISIS_SNMP_ADJ_STATE_UP;
+ break;
+ }
+
+ return SNMP_INTEGER(val);
+
+ case ISIS_ISADJ_3WAYSTATE:
+ return SNMP_INTEGER(adj->threeway_state);
+
+ case ISIS_ISADJ_NEIGHSNPAADDRESS: {
+ const char *snpa = (char *)snpa_print(adj->snpa);
+ *var_len = strlen(snpa);
+ return (uint8_t *)snpa;
+ }
+
+ case ISIS_ISADJ_NEIGHSYSTYPE:
+ val = ISIS_SNMP_ADJ_NEIGHTYPE_UNKNOWN;
+
+ switch (adj->sys_type) {
+ case ISIS_SYSTYPE_UNKNOWN:
+ case ISIS_SYSTYPE_ES:
+ val = ISIS_SNMP_ADJ_NEIGHTYPE_UNKNOWN;
+ break;
+
+ case ISIS_SYSTYPE_IS:
+ val = ISIS_SNMP_ADJ_NEIGHTYPE_IS_L1_L2;
+ break;
+
+ case ISIS_SYSTYPE_L1_IS:
+ val = ISIS_SNMP_ADJ_NEIGHTYPE_IS_L1;
+ break;
+
+ case ISIS_SYSTYPE_L2_IS:
+ val = ISIS_SNMP_ADJ_NEIGHTYPE_IS_L2;
+ break;
+ }
+
+ return SNMP_INTEGER(val);
+
+ case ISIS_ISADJ_NEIGHSYSID:
+ *var_len = sizeof(adj->sysid);
+ return adj->sysid;
+
+ case ISIS_ISADJ_NBREXTENDEDCIRCID:
+ return SNMP_INTEGER(adj->ext_circuit_id != 0 ? 1 : 0);
+
+ case ISIS_ISADJ_USAGE:
+ /* It seems that no value conversion is required */
+ return SNMP_INTEGER(adj->adj_usage);
+
+ case ISIS_ISADJ_HOLDTIMER:
+ /*
+ * It seems that we want remaining timer
+ */
+ if (adj->last_upd != 0) {
+ val = isis_snmp_time();
+ if (val < (adj->last_upd + adj->hold_time))
+ return SNMP_INTEGER(adj->last_upd
+ + adj->hold_time - val);
+ }
+ /* Not running or just expired */
+ return SNMP_INTEGER(0);
+
+ case ISIS_ISADJ_NEIGHPRIORITY:
+ return SNMP_INTEGER(adj->prio[adj->level - 1]);
+
+ case ISIS_ISADJ_LASTUPTIME:
+ if (adj->flaps == 0)
+ return SNMP_INTEGER(0);
+
+ up_ticks = netsnmp_get_agent_uptime();
+
+ now_time = isis_snmp_time();
+
+ if (adj->last_flap >= now_time)
+ return SNMP_INTEGER(up_ticks);
+
+ delta_ticks = (now_time - adj->last_flap) * 10;
+
+ if (up_ticks < delta_ticks)
+ return SNMP_INTEGER(up_ticks);
+
+ return SNMP_INTEGER((uint32_t)(up_ticks - delta_ticks));
+
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+static uint8_t *isis_snmp_find_isadj_area(struct variable *v, oid *name,
+ size_t *length, int exact,
+ size_t *var_len,
+ WriteMethod **write_method)
+{
+ /* Index circuit-id: 1-255 + adj-id: 1-... */
+ oid *oid_idx;
+ size_t oid_idx_len;
+ int res;
+ struct isis_adjacency *adj;
+ oid data_idx;
+ uint8_t *data;
+ size_t data_len;
+
+ *write_method = NULL;
+
+ if (*length <= v->namelen) {
+ oid_idx = NULL;
+ oid_idx_len = 0;
+ } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
+ oid_idx = NULL;
+ oid_idx_len = 0;
+ } else {
+ oid_idx = name + v->namelen;
+ oid_idx_len = *length - v->namelen;
+ }
+ if (exact) {
+ res = isis_snmp_adj_lookup_exact(oid_idx, oid_idx_len,
+ ISIS_SNMP_ADJ_DATA_AREA_ADDR,
+ &adj, NULL, &data, &data_len);
+
+ if (!res || oid_idx_len != 3)
+ return NULL;
+
+ } else {
+ res = isis_snmp_adj_lookup_next(
+ oid_idx, oid_idx_len, ISIS_SNMP_ADJ_DATA_AREA_ADDR,
+ &adj, &data_idx, &data, &data_len);
+ if (!res)
+ return NULL;
+
+ /* Copy the name out */
+ memcpy(name, v->name, v->namelen * sizeof(oid));
+
+ /* Append index */
+ name[v->namelen] = adj->circuit->snmp_id;
+ name[v->namelen + 1] = adj->snmp_idx;
+ name[v->namelen + 2] = data_idx;
+
+ /* Set length */
+ *length = v->namelen + 3;
+ }
+
+ switch (v->magic) {
+ case ISIS_ISADJAREA_ADDRESS:
+ *var_len = data_len;
+ return data;
+
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+static uint8_t *isis_snmp_find_isadj_ipaddr(struct variable *v, oid *name,
+ size_t *length, int exact,
+ size_t *var_len,
+ WriteMethod **write_method)
+{
+ /* Index circuit-id 1-255 + adj-id 1-... */
+ oid *oid_idx;
+ size_t oid_idx_len;
+ int res;
+ struct isis_adjacency *adj;
+ oid data_idx;
+ uint8_t *data;
+ size_t data_len;
+
+ *write_method = NULL;
+
+ if (*length <= v->namelen) {
+ oid_idx = NULL;
+ oid_idx_len = 0;
+ } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
+ oid_idx = NULL;
+ oid_idx_len = 0;
+ } else {
+ oid_idx = name + v->namelen;
+ oid_idx_len = *length - v->namelen;
+ }
+ if (exact) {
+ res = isis_snmp_adj_lookup_exact(oid_idx, oid_idx_len,
+ ISIS_SNMP_ADJ_DATA_IP_ADDR,
+ &adj, NULL, &data, &data_len);
+
+ if (!res || oid_idx_len != 3)
+ return NULL;
+ } else {
+ res = isis_snmp_adj_lookup_next(
+ oid_idx, oid_idx_len, ISIS_SNMP_ADJ_DATA_IP_ADDR, &adj,
+ &data_idx, &data, &data_len);
+ if (!res)
+ return NULL;
+
+ /* Copy the name out */
+ memcpy(name, v->name, v->namelen * sizeof(oid));
+
+ /* Append index */
+ name[v->namelen] = adj->circuit->snmp_id;
+ name[v->namelen + 1] = adj->snmp_idx;
+ name[v->namelen + 2] = data_idx;
+
+ /* Set length */
+ *length = v->namelen + 3;
+ }
+
+ switch (v->magic) {
+ case ISIS_ISADJIPADDR_TYPE:
+ if (data_len == 4)
+ return SNMP_INTEGER(ISIS_SNMP_INET_TYPE_V4);
+
+ return SNMP_INTEGER(ISIS_SNMP_INET_TYPE_V6);
+
+ case ISIS_ISADJIPADDR_ADDRESS:
+ *var_len = data_len;
+ return data;
+
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+static uint8_t *isis_snmp_find_isadj_prot_supp(struct variable *v, oid *name,
+ size_t *length, int exact,
+ size_t *var_len,
+ WriteMethod **write_method)
+{
+ /* Index circuit-id 1-255 + adj-id 1-... */
+ oid *oid_idx;
+ size_t oid_idx_len;
+ int res;
+ struct isis_adjacency *adj;
+ oid data_idx;
+ uint8_t *data;
+ size_t data_len;
+
+ *write_method = NULL;
+
+ if (*length <= v->namelen) {
+ oid_idx = NULL;
+ oid_idx_len = 0;
+ } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
+ oid_idx = NULL;
+ oid_idx_len = 0;
+ } else {
+ oid_idx = name + v->namelen;
+ oid_idx_len = *length - v->namelen;
+ }
+ if (exact) {
+ res = isis_snmp_adj_lookup_exact(oid_idx, oid_idx_len,
+ ISIS_SNMP_ADJ_DATA_PROTO, &adj,
+ NULL, &data, &data_len);
+
+ if (!res || oid_idx_len != 3)
+ return NULL;
+
+ } else {
+ res = isis_snmp_adj_lookup_next(oid_idx, oid_idx_len,
+ ISIS_SNMP_ADJ_DATA_PROTO, &adj,
+ &data_idx, &data, &data_len);
+ if (!res)
+ return NULL;
+
+ /* Copy the name out */
+ memcpy(name, v->name, v->namelen * sizeof(oid));
+
+ /* Append index */
+ name[v->namelen] = adj->circuit->snmp_id;
+ name[v->namelen + 1] = adj->snmp_idx;
+ name[v->namelen + 2] = data_idx;
+
+ /* Set length */
+ *length = v->namelen + 3;
+ }
+
+ switch (v->magic) {
+ case ISIS_ISADJPROTSUPP_PROTOCOL:
+ return SNMP_INTEGER(*data);
+
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+
+/* Register ISIS-MIB. */
+static int isis_snmp_init(struct thread_master *tm)
+{
+ struct isis_func_to_prefix *h2f = isis_func_to_prefix_arr;
+ struct variable *v;
+
+ for (size_t off = 0; off < isis_var_count; off++) {
+ v = &isis_var_arr[off];
+
+ if (v->findVar != h2f->ihtp_func) {
+ /* Next table */
+ h2f++;
+ assert(h2f < (isis_func_to_prefix_arr
+ + isis_func_to_prefix_count));
+ assert(v->findVar == h2f->ihtp_func);
+ }
+
+ v->namelen = h2f->ihtp_pref_len + 1;
+ memcpy(v->name, h2f->ihtp_pref_oid,
+ h2f->ihtp_pref_len * sizeof(oid));
+ v->name[h2f->ihtp_pref_len] = v->magic;
+ }
+
+
+ smux_init(tm);
+ REGISTER_MIB("mibII/isis", isis_var_arr, variable, isis_oid);
+ return 0;
+}
+
+/*
+ * ISIS notification functions: we have one function per notification
+ */
+static int isis_snmp_trap_throttle(oid trap_id)
+{
+ time_t time_now;
+ struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+ if (isis == NULL || !isis->snmp_notifications || !smux_enabled())
+ return 0;
+
+ time_now = isis_snmp_time();
+
+ if ((isis_snmp_trap_timestamp[trap_id] + 5) > time_now)
+ /* Throttle trap rate at 1 in 5 secs */
+ return 0;
+
+ isis_snmp_trap_timestamp[trap_id] = time_now;
+ return 1;
+}
+
+static int isis_snmp_db_overload_update(const struct isis_area *area)
+{
+ netsnmp_variable_list *notification_vars;
+ long val;
+ uint32_t off;
+
+ if (!isis_snmp_trap_throttle(ISIS_TRAP_DB_OVERLOAD))
+ return 0;
+
+ notification_vars = NULL;
+
+ /* Put in trap value */
+ snmp_varlist_add_variable(&notification_vars, isis_snmp_trap_var,
+ ARRAY_SIZE(isis_snmp_trap_var), ASN_OBJECT_ID,
+ (uint8_t *)&isis_snmp_trap_val_db_overload,
+ sizeof(isis_snmp_trap_val_db_overload));
+
+ /* Prepare data */
+ val = area->is_type;
+
+ snmp_varlist_add_variable(
+ &notification_vars, isis_snmp_trap_data_var_sys_level_index,
+ ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_index), INTEGER,
+ (uint8_t *)&val, sizeof(val));
+
+ /* Patch sys_level_state with proper index */
+ off = ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_state) - 1;
+ isis_snmp_trap_data_var_sys_level_state[off] = val;
+
+ /* Prepare data */
+ if (area->overload_bit)
+ val = ISIS_SNMP_LEVEL_STATE_OVERLOADED;
+ else
+ val = ISIS_SNMP_LEVEL_STATE_ON;
+
+ snmp_varlist_add_variable(
+ &notification_vars, isis_snmp_trap_data_var_sys_level_state,
+ ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_state), INTEGER,
+ (uint8_t *)&val, sizeof(val));
+
+ send_v2trap(notification_vars);
+ snmp_free_varbind(notification_vars);
+ smux_events_update();
+ return 0;
+}
+
+static int isis_snmp_lsp_exceed_max_update(const struct isis_area *area,
+ const uint8_t *lsp_id)
+{
+ netsnmp_variable_list *notification_vars;
+ long val;
+
+ if (!isis_snmp_trap_throttle(ISIS_TRAP_LSP_EXCEED_MAX))
+ return 0;
+
+ notification_vars = NULL;
+
+ /* Put in trap value */
+ snmp_varlist_add_variable(&notification_vars, isis_snmp_trap_var,
+ ARRAY_SIZE(isis_snmp_trap_var), ASN_OBJECT_ID,
+ (uint8_t *)&isis_snmp_trap_val_lsp_exceed_max,
+ sizeof(isis_snmp_trap_val_lsp_exceed_max));
+
+ /* Prepare data */
+ val = area->is_type;
+
+ snmp_varlist_add_variable(
+ &notification_vars, isis_snmp_trap_data_var_sys_level_index,
+ ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_index), INTEGER,
+ (uint8_t *)&val, sizeof(val));
+
+ snmp_varlist_add_variable(
+ &notification_vars, isis_snmp_trap_data_var_pdu_lsp_id,
+ ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_id), STRING, lsp_id,
+ ISIS_SYS_ID_LEN + 2);
+
+ send_v2trap(notification_vars);
+ snmp_free_varbind(notification_vars);
+ smux_events_update();
+ return 0;
+}
+
+
+/*
+ * A common function to handle popular combination of trap objects
+ * isisNotificationSysLevelIndex,
+ * optional-object-a
+ * isisNotificationCircIfIndex,
+ * optional-object-b
+ */
+static void isis_snmp_update_worker_a(const struct isis_circuit *circuit,
+ oid trap_id, const oid *oid_a,
+ size_t oid_a_len, uint8_t type_a,
+ const void *data_a, size_t data_a_len,
+ const oid *oid_b, size_t oid_b_len,
+ uint8_t type_b, const void *data_b,
+ size_t data_b_len)
+{
+ netsnmp_variable_list *notification_vars = NULL;
+ oid var_name[MAX_OID_LEN];
+ size_t var_count;
+ long val;
+
+ /* Sanity */
+ if (trap_id != ISIS_TRAP_ID_LEN_MISMATCH
+ && trap_id != ISIS_TRAP_MAX_AREA_ADDR_MISMATCH
+ && trap_id != ISIS_TRAP_OWN_LSP_PURGE
+ && trap_id != ISIS_TRAP_SEQNO_SKIPPED
+ && trap_id != ISIS_TRAP_AUTHEN_TYPE_FAILURE
+ && trap_id != ISIS_TRAP_AUTHEN_FAILURE
+ && trap_id != ISIS_TRAP_REJ_ADJACENCY)
+ return;
+
+ /* Put in trap value */
+ memcpy(var_name, isis_snmp_notifications,
+ sizeof(isis_snmp_notifications));
+ var_count = ARRAY_SIZE(isis_snmp_notifications);
+ var_name[var_count++] = trap_id;
+
+ /* Put in trap value */
+ snmp_varlist_add_variable(&notification_vars, isis_snmp_trap_var,
+ ARRAY_SIZE(isis_snmp_trap_var), ASN_OBJECT_ID,
+ (uint8_t *)var_name, var_count * sizeof(oid));
+
+ val = circuit->is_type;
+ snmp_varlist_add_variable(
+ &notification_vars, isis_snmp_trap_data_var_sys_level_index,
+ ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_index), INTEGER,
+ (uint8_t *)&val, sizeof(val));
+
+ if (oid_a_len != 0) {
+ if (oid_a == NULL || data_a == NULL || data_a_len == 0)
+ return;
+
+ snmp_varlist_add_variable(&notification_vars, oid_a, oid_a_len,
+ type_a, (uint8_t *)data_a,
+ data_a_len);
+ }
+
+ if (circuit->interface == NULL)
+ val = 0;
+ else
+ val = circuit->interface->ifindex;
+
+ snmp_varlist_add_variable(
+ &notification_vars, isis_snmp_trap_data_var_circ_if_index,
+ ARRAY_SIZE(isis_snmp_trap_data_var_circ_if_index), UNSIGNED32,
+ (uint8_t *)&val, sizeof(val));
+
+
+ if (oid_b_len != 0) {
+ if (oid_b == NULL || data_b == NULL || data_b_len == 0)
+ return;
+
+ snmp_varlist_add_variable(&notification_vars, oid_b, oid_b_len,
+ type_b, (uint8_t *)data_b,
+ data_b_len);
+ }
+
+ send_v2trap(notification_vars);
+ snmp_free_varbind(notification_vars);
+ smux_events_update();
+}
+
+/*
+ * A common function to handle popular combination of trap objects
+ * isisNotificationSysLevelIndex,
+ * isisNotificationCircIfIndex,
+ * optional-var-a
+ * optional-var-b
+ *
+ * Note: the only difference with worker_a is order of circ-if-index vs
+ * optional-var-a
+ */
+static void isis_snmp_update_worker_b(const struct isis_circuit *circuit,
+ oid trap_id, const oid *oid_a,
+ size_t oid_a_len, uint8_t type_a,
+ const void *data_a, size_t data_a_len,
+ const oid *oid_b, size_t oid_b_len,
+ uint8_t type_b, const void *data_b,
+ size_t data_b_len)
+{
+ netsnmp_variable_list *notification_vars = NULL;
+ oid var_name[MAX_OID_LEN];
+ size_t var_count;
+ long val;
+
+ /* Sanity */
+ if (trap_id != ISIS_TRAP_VERSION_SKEW
+ && trap_id != ISIS_TRAP_LSP_TOO_LARGE
+ && trap_id != ISIS_TRAP_ADJ_STATE_CHANGE)
+ return;
+
+ /* Put in trap value */
+ memcpy(var_name, isis_snmp_notifications,
+ sizeof(isis_snmp_notifications));
+ var_count = ARRAY_SIZE(isis_snmp_notifications);
+ var_name[var_count++] = trap_id;
+
+ /* Put in trap value */
+ snmp_varlist_add_variable(&notification_vars, isis_snmp_trap_var,
+ ARRAY_SIZE(isis_snmp_trap_var), ASN_OBJECT_ID,
+ (uint8_t *)var_name, var_count * sizeof(oid));
+
+ val = circuit->is_type;
+ snmp_varlist_add_variable(
+ &notification_vars, isis_snmp_trap_data_var_sys_level_index,
+ ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_index), INTEGER,
+ (uint8_t *)&val, sizeof(val));
+
+ if (circuit->interface == NULL)
+ val = 0;
+ else
+ val = circuit->interface->ifindex;
+
+ snmp_varlist_add_variable(
+ &notification_vars, isis_snmp_trap_data_var_circ_if_index,
+ ARRAY_SIZE(isis_snmp_trap_data_var_circ_if_index), UNSIGNED32,
+ (uint8_t *)&val, sizeof(val));
+
+
+ if (oid_a_len != 0) {
+ if (oid_a == NULL || data_a == NULL || data_a_len == 0)
+ return;
+
+ snmp_varlist_add_variable(&notification_vars, oid_a, oid_a_len,
+ type_a, (uint8_t *)data_a,
+ data_a_len);
+ }
+
+ if (oid_b_len != 0) {
+ if (oid_b == NULL || data_b == NULL || data_b_len == 0)
+ return;
+
+ snmp_varlist_add_variable(&notification_vars, oid_b, oid_b_len,
+ type_b, (uint8_t *)data_b,
+ data_b_len);
+ }
+
+ send_v2trap(notification_vars);
+ snmp_free_varbind(notification_vars);
+ smux_events_update();
+}
+
+
+static int isis_snmp_id_len_mismatch_update(const struct isis_circuit *circuit,
+ uint8_t rcv_id, const char *raw_pdu,
+ size_t raw_pdu_len)
+{
+ long val;
+
+ if (!isis_snmp_trap_throttle(ISIS_TRAP_ID_LEN_MISMATCH))
+ return 0;
+
+ val = rcv_id;
+
+ if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN)
+ raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN;
+
+ isis_snmp_update_worker_a(
+ circuit, ISIS_TRAP_ID_LEN_MISMATCH,
+ isis_snmp_trap_data_var_pdu_field_len,
+ ARRAY_SIZE(isis_snmp_trap_data_var_pdu_field_len), UNSIGNED32,
+ &val, sizeof(val), isis_snmp_trap_data_var_pdu_fragment,
+ ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING,
+ raw_pdu, raw_pdu_len);
+ return 0;
+}
+
+static int
+isis_snmp_max_area_addr_mismatch_update(const struct isis_circuit *circuit,
+ uint8_t max_addrs, const char *raw_pdu,
+ size_t raw_pdu_len)
+{
+ long val;
+
+ if (!isis_snmp_trap_throttle(ISIS_TRAP_MAX_AREA_ADDR_MISMATCH))
+ return 0;
+
+ val = max_addrs;
+
+ if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN)
+ raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN;
+
+ isis_snmp_update_worker_a(
+ circuit, ISIS_TRAP_MAX_AREA_ADDR_MISMATCH,
+ isis_snmp_trap_data_var_pdu_max_area_addr,
+ ARRAY_SIZE(isis_snmp_trap_data_var_pdu_max_area_addr),
+ UNSIGNED32, &val, sizeof(val),
+ isis_snmp_trap_data_var_pdu_fragment,
+ ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING,
+ raw_pdu, raw_pdu_len);
+ return 0;
+}
+
+static int isis_snmp_own_lsp_purge_update(const struct isis_circuit *circuit,
+ const uint8_t *lsp_id)
+{
+ if (!isis_snmp_trap_throttle(ISIS_TRAP_OWN_LSP_PURGE))
+ return 0;
+
+ isis_snmp_update_worker_a(
+ circuit, ISIS_TRAP_OWN_LSP_PURGE, NULL, 0, STRING, NULL, 0,
+ isis_snmp_trap_data_var_pdu_lsp_id,
+ ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_id), STRING, lsp_id,
+ ISIS_SYS_ID_LEN + 2);
+ return 0;
+}
+
+static int isis_snmp_seqno_skipped_update(const struct isis_circuit *circuit,
+ const uint8_t *lsp_id)
+{
+ if (!isis_snmp_trap_throttle(ISIS_TRAP_SEQNO_SKIPPED))
+ return 0;
+
+ isis_snmp_update_worker_a(
+ circuit, ISIS_TRAP_SEQNO_SKIPPED, NULL, 0, STRING, NULL, 0,
+ isis_snmp_trap_data_var_pdu_lsp_id,
+ ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_id), STRING, lsp_id,
+ ISIS_SYS_ID_LEN + 2);
+ return 0;
+}
+
+static int
+isis_snmp_authentication_type_failure_update(const struct isis_circuit *circuit,
+ const char *raw_pdu,
+ size_t raw_pdu_len)
+{
+ if (!isis_snmp_trap_throttle(ISIS_TRAP_AUTHEN_TYPE_FAILURE))
+ return 0;
+
+ if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN)
+ raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN;
+
+ isis_snmp_update_worker_a(
+ circuit, ISIS_TRAP_AUTHEN_TYPE_FAILURE, NULL, 0, STRING, NULL,
+ 0, isis_snmp_trap_data_var_pdu_fragment,
+ ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING,
+ raw_pdu, raw_pdu_len);
+ return 0;
+}
+
+static int
+isis_snmp_authentication_failure_update(const struct isis_circuit *circuit,
+ char const *raw_pdu, size_t raw_pdu_len)
+{
+ if (!isis_snmp_trap_throttle(ISIS_TRAP_AUTHEN_FAILURE))
+ return 0;
+
+ if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN)
+ raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN;
+
+ isis_snmp_update_worker_a(
+ circuit, ISIS_TRAP_AUTHEN_FAILURE, NULL, 0, STRING, NULL, 0,
+ isis_snmp_trap_data_var_pdu_fragment,
+ ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING,
+ raw_pdu, raw_pdu_len);
+ return 0;
+}
+
+static int isis_snmp_version_skew_update(const struct isis_circuit *circuit,
+ uint8_t version, const char *raw_pdu,
+ size_t raw_pdu_len)
+{
+ long val;
+
+ if (!isis_snmp_trap_throttle(ISIS_TRAP_VERSION_SKEW))
+ return 0;
+
+ val = version;
+
+ if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN)
+ raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN;
+
+ isis_snmp_update_worker_b(
+ circuit, ISIS_TRAP_VERSION_SKEW,
+ isis_snmp_trap_data_var_pdu_proto_ver,
+ ARRAY_SIZE(isis_snmp_trap_data_var_pdu_proto_ver), UNSIGNED32,
+ &val, sizeof(val), isis_snmp_trap_data_var_pdu_fragment,
+ ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING,
+ raw_pdu, raw_pdu_len);
+ return 0;
+}
+
+static int isis_snmp_area_mismatch_update(const struct isis_circuit *circuit,
+ const char *raw_pdu,
+ size_t raw_pdu_len)
+{
+ /*
+ * This is a special case because
+ * it does not include isisNotificationSysLevelIndex
+ */
+ netsnmp_variable_list *notification_vars;
+ long val;
+
+ if (!isis_snmp_trap_throttle(ISIS_TRAP_AREA_MISMATCH))
+ return 0;
+
+ notification_vars = NULL;
+
+ /* Put in trap value */
+ snmp_varlist_add_variable(&notification_vars, isis_snmp_trap_var,
+ ARRAY_SIZE(isis_snmp_trap_var), ASN_OBJECT_ID,
+ (uint8_t *)&isis_snmp_trap_val_area_mismatch,
+ sizeof(isis_snmp_trap_val_area_mismatch));
+
+
+ if (circuit->interface == NULL)
+ val = 0;
+ else
+ val = circuit->interface->ifindex;
+
+ snmp_varlist_add_variable(
+ &notification_vars, isis_snmp_trap_data_var_circ_if_index,
+ ARRAY_SIZE(isis_snmp_trap_data_var_circ_if_index), UNSIGNED32,
+ (uint8_t *)&val, sizeof(val));
+
+
+ if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN)
+ raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN;
+
+ snmp_varlist_add_variable(
+ &notification_vars, isis_snmp_trap_data_var_pdu_fragment,
+ ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING,
+ raw_pdu, raw_pdu_len);
+
+ send_v2trap(notification_vars);
+ snmp_free_varbind(notification_vars);
+ smux_events_update();
+
+ return 0;
+}
+
+static int isis_snmp_reject_adjacency_update(const struct isis_circuit *circuit,
+ const char *raw_pdu,
+ size_t raw_pdu_len)
+{
+ if (!isis_snmp_trap_throttle(ISIS_TRAP_REJ_ADJACENCY))
+ return 0;
+
+ if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN)
+ raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN;
+
+ isis_snmp_update_worker_a(
+ circuit, ISIS_TRAP_REJ_ADJACENCY, NULL, 0, STRING, NULL, 0,
+ isis_snmp_trap_data_var_pdu_fragment,
+ ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING,
+ raw_pdu, raw_pdu_len);
+ return 0;
+}
+
+static int isis_snmp_lsp_too_large_update(const struct isis_circuit *circuit,
+ uint32_t pdu_size,
+ const uint8_t *lsp_id)
+{
+ if (!isis_snmp_trap_throttle(ISIS_TRAP_LSP_TOO_LARGE))
+ return 0;
+
+ isis_snmp_update_worker_b(
+ circuit, ISIS_TRAP_LSP_TOO_LARGE,
+ isis_snmp_trap_data_var_pdu_lsp_size,
+ ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_size), UNSIGNED32,
+ &pdu_size, sizeof(pdu_size), isis_snmp_trap_data_var_pdu_lsp_id,
+ ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_id), STRING, lsp_id,
+ ISIS_SYS_ID_LEN + 2);
+ return 0;
+}
+
+
+static int isis_snmp_adj_state_change_update(const struct isis_adjacency *adj)
+{
+ uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
+ long val;
+ struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+ if (isis == NULL || !isis->snmp_notifications || !smux_enabled())
+ return 0;
+
+ /* Prepare data */
+ memcpy(lsp_id, adj->sysid, ISIS_SYS_ID_LEN);
+ lsp_id[ISIS_SYS_ID_LEN] = 0;
+ lsp_id[ISIS_SYS_ID_LEN + 1] = 0;
+
+ val = ISIS_SNMP_ADJ_STATE_DOWN;
+
+ switch (adj->adj_state) {
+ case ISIS_ADJ_UNKNOWN:
+ val = ISIS_SNMP_ADJ_STATE_DOWN;
+ break;
+
+ case ISIS_ADJ_INITIALIZING:
+ val = ISIS_SNMP_ADJ_STATE_INITIALIZING;
+ break;
+
+ case ISIS_ADJ_UP:
+ val = ISIS_SNMP_ADJ_STATE_UP;
+ break;
+
+ case ISIS_ADJ_DOWN:
+ val = ISIS_SNMP_ADJ_STATE_FAILED;
+ break;
+ }
+
+ isis_snmp_update_worker_b(
+ adj->circuit, ISIS_TRAP_ADJ_STATE_CHANGE,
+ isis_snmp_trap_data_var_pdu_lsp_id,
+ ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_id), STRING, lsp_id,
+ ISIS_SYS_ID_LEN + 2, isis_snmp_trap_data_var_adj_state,
+ ARRAY_SIZE(isis_snmp_trap_data_var_adj_state), INTEGER, &val,
+ sizeof(val));
+ return 0;
+}
+
+static int isis_snmp_lsp_error_update(const struct isis_circuit *circuit,
+ const uint8_t *lsp_id,
+ char const *raw_pdu, size_t raw_pdu_len)
+{
+ /*
+ * This is a special case because
+ * it have more variables
+ */
+ netsnmp_variable_list *notification_vars;
+ long val;
+
+ if (!isis_snmp_trap_throttle(ISIS_TRAP_LSP_ERROR))
+ return 0;
+
+ notification_vars = NULL;
+
+ /* Put in trap value */
+ snmp_varlist_add_variable(&notification_vars, isis_snmp_trap_var,
+ ARRAY_SIZE(isis_snmp_trap_var), ASN_OBJECT_ID,
+ (uint8_t *)&isis_snmp_trap_val_lsp_error,
+ sizeof(isis_snmp_trap_val_lsp_error));
+
+ /* Prepare data */
+ val = circuit->is_type;
+
+ snmp_varlist_add_variable(
+ &notification_vars, isis_snmp_trap_data_var_sys_level_index,
+ ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_index), INTEGER,
+ (uint8_t *)&val, sizeof(val));
+
+
+ snmp_varlist_add_variable(
+ &notification_vars, isis_snmp_trap_data_var_pdu_lsp_id,
+ ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_id), STRING, lsp_id,
+ ISIS_SYS_ID_LEN + 2);
+
+ /* Prepare data */
+ if (circuit->interface == NULL)
+ val = 0;
+ else
+ val = circuit->interface->ifindex;
+
+ snmp_varlist_add_variable(
+ &notification_vars, isis_snmp_trap_data_var_circ_if_index,
+ ARRAY_SIZE(isis_snmp_trap_data_var_circ_if_index), UNSIGNED32,
+ (uint8_t *)&val, sizeof(val));
+
+ /* Prepare data */
+ if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN)
+ raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN;
+
+ snmp_varlist_add_variable(
+ &notification_vars, isis_snmp_trap_data_var_pdu_fragment,
+ ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING,
+ raw_pdu, raw_pdu_len);
+
+ /* Prepare data */
+ val = 0;
+
+ snmp_varlist_add_variable(
+ &notification_vars, isis_snmp_trap_data_var_error_offset,
+ ARRAY_SIZE(isis_snmp_trap_data_var_error_offset), UNSIGNED32,
+ (uint8_t *)&val, sizeof(val));
+
+ /* Prepare data */
+ val = 0;
+
+ snmp_varlist_add_variable(
+ &notification_vars, isis_snmp_trap_data_var_error_tlv_type,
+ ARRAY_SIZE(isis_snmp_trap_data_var_error_tlv_type), UNSIGNED32,
+ (uint8_t *)&val, sizeof(val));
+
+ send_v2trap(notification_vars);
+ snmp_free_varbind(notification_vars);
+ smux_events_update();
+ return 0;
+}
+
+
+static int isis_snmp_module_init(void)
+{
+ hook_register(isis_hook_db_overload, isis_snmp_db_overload_update);
+ hook_register(isis_hook_lsp_exceed_max,
+ isis_snmp_lsp_exceed_max_update);
+ hook_register(isis_hook_id_len_mismatch,
+ isis_snmp_id_len_mismatch_update);
+ hook_register(isis_hook_max_area_addr_mismatch,
+ isis_snmp_max_area_addr_mismatch_update);
+ hook_register(isis_hook_own_lsp_purge, isis_snmp_own_lsp_purge_update);
+ hook_register(isis_hook_seqno_skipped, isis_snmp_seqno_skipped_update);
+ hook_register(isis_hook_authentication_type_failure,
+ isis_snmp_authentication_type_failure_update);
+ hook_register(isis_hook_authentication_failure,
+ isis_snmp_authentication_failure_update);
+ hook_register(isis_hook_version_skew, isis_snmp_version_skew_update);
+ hook_register(isis_hook_area_mismatch, isis_snmp_area_mismatch_update);
+ hook_register(isis_hook_reject_adjacency,
+ isis_snmp_reject_adjacency_update);
+ hook_register(isis_hook_lsp_too_large, isis_snmp_lsp_too_large_update);
+ hook_register(isis_hook_adj_state_change,
+ isis_snmp_adj_state_change_update);
+ hook_register(isis_hook_lsp_error, isis_snmp_lsp_error_update);
+
+ hook_register(frr_late_init, isis_snmp_init);
+ return 0;
+}
+
+FRR_MODULE_SETUP(.name = "isis_snmp", .version = FRR_VERSION,
+ .description = "isis AgentX SNMP module",
+ .init = isis_snmp_module_init, )
diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c
index 22dfee994f..7bcc6fea90 100644
--- a/isisd/isis_spf.c
+++ b/isisd/isis_spf.c
@@ -1821,6 +1821,7 @@ static int isis_run_spf_cb(struct thread *thread)
struct isis_spf_run *run = THREAD_ARG(thread);
struct isis_area *area = run->area;
int level = run->level;
+ int have_run = 0;
XFREE(MTYPE_ISIS_SPF_RUN, run);
area->spf_timer[level - 1] = NULL;
@@ -1839,15 +1840,24 @@ static int isis_run_spf_cb(struct thread *thread)
zlog_debug("ISIS-SPF (%s) L%d SPF needed, periodic SPF",
area->area_tag, level);
- if (area->ip_circuits)
+ if (area->ip_circuits) {
isis_run_spf_with_protection(
area, area->spftree[SPFTREE_IPV4][level - 1]);
- if (area->ipv6_circuits)
+ have_run = 1;
+ }
+ if (area->ipv6_circuits) {
isis_run_spf_with_protection(
area, area->spftree[SPFTREE_IPV6][level - 1]);
- if (area->ipv6_circuits && isis_area_ipv6_dstsrc_enabled(area))
+ have_run = 1;
+ }
+ if (area->ipv6_circuits && isis_area_ipv6_dstsrc_enabled(area)) {
isis_run_spf_with_protection(
area, area->spftree[SPFTREE_DSTSRC][level - 1]);
+ have_run = 1;
+ }
+
+ if (have_run)
+ area->spf_run_count[level]++;
isis_area_verify_routes(area);
diff --git a/isisd/isisd.c b/isisd/isisd.c
index a802bac13b..487a902c06 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -89,6 +89,10 @@ static struct isis_master isis_master;
/* ISIS process wide configuration pointer to export. */
struct isis_master *im;
+#ifndef FABRICD
+DEFINE_HOOK(isis_hook_db_overload, (const struct isis_area *area), (area));
+#endif /* ifndef FABRICD */
+
/*
* Prototypes.
*/
@@ -214,6 +218,7 @@ struct isis *isis_new(const char *vrf_name)
isis->area_list = list_new();
isis->init_circ_list = list_new();
isis->uptime = time(NULL);
+ isis->snmp_notifications = 1;
dyn_cache_init(isis);
return isis;
@@ -2563,6 +2568,14 @@ void isis_area_overload_bit_set(struct isis_area *area, bool overload_bit)
if (new_overload_bit != area->overload_bit) {
area->overload_bit = new_overload_bit;
+
+ if (new_overload_bit)
+ area->overload_counter++;
+
+#ifndef FABRICD
+ hook_call(isis_hook_db_overload, area);
+#endif /* ifndef FABRICD */
+
lsp_regenerate_schedule(area, IS_LEVEL_1 | IS_LEVEL_2, 1);
}
#ifndef FABRICD
diff --git a/isisd/isisd.h b/isisd/isisd.h
index 22d9c6236d..1b0ec2b4f0 100644
--- a/isisd/isisd.h
+++ b/isisd/isisd.h
@@ -63,6 +63,8 @@ extern void isis_cli_init(void);
all_vrf = strmatch(vrf_name, "all"); \
}
+#define SNMP_CIRCUITS_MAX (512)
+
extern struct zebra_privs_t isisd_privs;
/* uncomment if you are a developer in bug hunt */
@@ -93,6 +95,9 @@ struct isis {
time_t uptime; /* when did we start */
struct thread *t_dync_clean; /* dynamic hostname cache cleanup thread */
uint32_t circuit_ids_used[8]; /* 256 bits to track circuit ids 1 through 255 */
+ struct isis_circuit *snmp_circuits[SNMP_CIRCUITS_MAX];
+ uint32_t snmp_circuit_id_last;
+ int snmp_notifications;
struct route_table *ext_info[REDIST_PROTOCOL_COUNT];
struct ldp_sync_info_cmd ldp_sync_cmd; /* MPLS LDP-IGP Sync */
@@ -168,6 +173,7 @@ struct isis_area {
char is_type; /* level-1 level-1-2 or level-2-only */
/* are we overloaded? */
char overload_bit;
+ uint32_t overload_counter;
/* L1/L2 router identifier for inter-area traffic */
char attached_bit_send;
char attached_bit_rcv_ignore;
@@ -180,6 +186,9 @@ struct isis_area {
int lsp_frag_threshold;
uint64_t lsp_gen_count[ISIS_LEVELS];
uint64_t lsp_purge_count[ISIS_LEVELS];
+ uint32_t lsp_exceeded_max_counter;
+ uint32_t lsp_seqno_skipped_counter;
+ uint64_t spf_run_count[ISIS_LEVELS];
int ip_circuits;
/* logging adjacency changes? */
uint8_t log_adj_changes;
@@ -220,10 +229,19 @@ struct isis_area {
pdu_counter_t pdu_rx_counters;
uint64_t lsp_rxmt_count;
+ /* Area counters */
+ uint64_t rej_adjacencies[2];
+ uint64_t auth_type_failures[2];
+ uint64_t auth_failures[2];
+ uint64_t id_len_mismatches[2];
+ uint64_t lsp_error_counter[2];
+
QOBJ_FIELDS
};
DECLARE_QOBJ_TYPE(isis_area)
+DECLARE_HOOK(isis_area_overload_bit_update, (struct isis_area * area), (area))
+
void isis_terminate(void);
void isis_finish(struct isis *isis);
void isis_master_init(struct thread_master *master);
diff --git a/isisd/subdir.am b/isisd/subdir.am
index 4be4efc118..98674a6881 100644
--- a/isisd/subdir.am
+++ b/isisd/subdir.am
@@ -17,6 +17,9 @@ vtysh_scan += \
isisd/isisd.c \
# end
vtysh_daemons += isisd
+if SNMP
+module_LTLIBRARIES += isisd/isisd_snmp.la
+endif
man8 += $(MANBUILD)/frr-isisd.8
endif
@@ -137,7 +140,12 @@ isisd_isisd_SOURCES = $(ISIS_SOURCES)
nodist_isisd_isisd_SOURCES = \
yang/frr-isisd.yang.c \
# end
-
+
+isisd_isisd_snmp_la_SOURCES = isisd/isis_snmp.c
+isisd_isisd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu99
+isisd_isisd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
+isisd_isisd_snmp_la_LIBADD = lib/libfrrsnmp.la
+
# Building fabricd
FABRICD_CPPFLAGS = -DFABRICD=1 $(AM_CPPFLAGS)
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 <zebra.h>
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+
+#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;
@@ -355,6 +359,23 @@ nbr_find_ldpid(uint32_t lsr_id)
}
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)
{
struct nbr n;
@@ -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/lib/agentx.c b/lib/agentx.c
index c8d7d75a81..c1ff7a61b1 100644
--- a/lib/agentx.c
+++ b/lib/agentx.c
@@ -246,6 +246,11 @@ DEFUN (no_agentx,
return CMD_WARNING_CONFIG_FAILED;
}
+int smux_enabled(void)
+{
+ return agentx_enabled;
+}
+
void smux_init(struct thread_master *tm)
{
agentx_tm = tm;
@@ -392,4 +397,9 @@ int smux_trap_multi_index(struct variable *vp, size_t vp_len, const oid *ename,
return 1;
}
+void smux_events_update(void)
+{
+ agentx_events_update();
+}
+
#endif /* SNMP_AGENTX */
diff --git a/lib/northbound.c b/lib/northbound.c
index 224951b22b..b6d3518285 100644
--- a/lib/northbound.c
+++ b/lib/northbound.c
@@ -1817,6 +1817,16 @@ int nb_oper_data_iterate(const char *xpath, struct yang_translator *translator,
/* Find the list entry pointer. */
nn = dn->schema->priv;
+ if (!nn->cbs.lookup_entry) {
+ flog_warn(
+ EC_LIB_NB_OPERATIONAL_DATA,
+ "%s: data path doesn't support iteration over operational data: %s",
+ __func__, xpath);
+ list_delete(&list_dnodes);
+ yang_dnode_free(dnode);
+ return NB_ERR;
+ }
+
list_entry =
nb_callback_lookup_entry(nn, list_entry, &list_keys);
if (list_entry == NULL) {
diff --git a/lib/smux.h b/lib/smux.h
index a263478a2e..57128b7928 100644
--- a/lib/smux.h
+++ b/lib/smux.h
@@ -103,6 +103,8 @@ struct index_oid {
#define SNMP_IP6ADDRESS(V) (*var_len = sizeof(struct in6_addr), (uint8_t *)&V)
+extern int smux_enabled(void);
+
extern void smux_init(struct thread_master *tm);
extern void smux_agentx_enable(void);
extern void smux_register_mib(const char *, struct variable *, size_t, int,
@@ -143,6 +145,8 @@ extern int smux_trap_multi_index(struct variable *vp, size_t vp_len,
struct index_oid *iname, size_t index_len,
const struct trap_object *trapobj,
size_t trapobjlen, uint8_t sptrap);
+
+extern void smux_events_update(void);
extern int oid_compare(const oid *, int, const oid *, int);
extern void oid2in_addr(oid[], int, struct in_addr *);
extern void oid2in6_addr(oid oid[], struct in6_addr *addr);
diff --git a/tests/topotests/isis-snmp/ce3/zebra.conf b/tests/topotests/isis-snmp/ce3/zebra.conf
new file mode 100644
index 0000000000..c6a5824d15
--- /dev/null
+++ b/tests/topotests/isis-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/isis-snmp/r1/isisd.conf b/tests/topotests/isis-snmp/r1/isisd.conf
new file mode 100644
index 0000000000..dd32d3b8a5
--- /dev/null
+++ b/tests/topotests/isis-snmp/r1/isisd.conf
@@ -0,0 +1,24 @@
+hostname r1
+log file isisd.log
+debug isis adj-packets
+debug isis events
+debug isis update-packets
+agentx
+!
+router isis 1
+ 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
+!
+interface r1-eth0
+ ip router isis 1
+ ipv6 router isis 1
+ isis circuit-type level-1
+!
+interface r1-eth1
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis circuit-type level-1
+!
diff --git a/tests/topotests/isis-snmp/r1/ldpd.conf b/tests/topotests/isis-snmp/r1/ldpd.conf
new file mode 100644
index 0000000000..4ec296ca5a
--- /dev/null
+++ b/tests/topotests/isis-snmp/r1/ldpd.conf
@@ -0,0 +1,26 @@
+hostname r1
+log file ldpd.log
+!
+debug mpls ldp zebra
+debug mpls ldp event
+debug mpls ldp errors
+debug mpls ldp sync
+agentx
+!
+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-eth0
+ !
+ interface r1-eth1
+ !
+ !
+!
+line vty
+!
diff --git a/tests/topotests/isis-snmp/r1/show_ip_route.ref b/tests/topotests/isis-snmp/r1/show_ip_route.ref
new file mode 100644
index 0000000000..dc8f19dad0
--- /dev/null
+++ b/tests/topotests/isis-snmp/r1/show_ip_route.ref
@@ -0,0 +1,143 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":1,
+ "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",
+ "interfaceIndex":3,
+ "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",
+ "interfaceIndex":4,
+ "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",
+ "interfaceIndex":3,
+ "interfaceName":"r1-eth1"
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":3,
+ "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",
+ "interfaceIndex":4,
+ "interfaceName":"r1-eth2"
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":4,
+ "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",
+ "interfaceIndex":3,
+ "interfaceName":"r1-eth1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.2.3",
+ "afi":"ipv4",
+ "interfaceIndex":4,
+ "interfaceName":"r1-eth2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-snmp/r1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-snmp/r1/show_yang_interface_isis_adjacencies.ref
new file mode 100644
index 0000000000..0391a79c1f
--- /dev/null
+++ b/tests/topotests/isis-snmp/r1/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1,42 @@
+{
+ "frr-interface:lib": {
+ "interface": [
+ {
+ "name": "r1-eth0",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0004",
+ "neighbor-extended-circuit-id": 2,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "name": "r1-eth1",
+ "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/isis-snmp/r1/snmpd.conf b/tests/topotests/isis-snmp/r1/snmpd.conf
new file mode 100644
index 0000000000..b37911da36
--- /dev/null
+++ b/tests/topotests/isis-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/isis-snmp/r1/zebra.conf b/tests/topotests/isis-snmp/r1/zebra.conf
new file mode 100644
index 0000000000..6ac341e431
--- /dev/null
+++ b/tests/topotests/isis-snmp/r1/zebra.conf
@@ -0,0 +1,24 @@
+log file zebra.log
+!
+hostname r1
+!
+debug zebra kernel
+debug zebra rib detailed
+debug zebra dplane detailed
+debug zebra nht
+!
+interface lo
+ ip address 1.1.1.1/32
+!
+interface r1-eth0
+ description to rt4
+ ip address 14.0.0.1/24
+!
+interface r1-eth1
+ description to rt3
+ ip address 13.0.0.1/24
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-snmp/r2/isisd.conf b/tests/topotests/isis-snmp/r2/isisd.conf
new file mode 100644
index 0000000000..4403d8913b
--- /dev/null
+++ b/tests/topotests/isis-snmp/r2/isisd.conf
@@ -0,0 +1,25 @@
+hostname r2
+log file isisd.log
+debug isis adj-packets
+debug isis events
+debug isis update-packets
+agentx
+!
+router isis 1
+ 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
+!
+interface r2-eth0
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis circuit-type level-1
+!
+interface r2-eth1
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis circuit-type level-1
+!
diff --git a/tests/topotests/isis-snmp/r2/ldpd.conf b/tests/topotests/isis-snmp/r2/ldpd.conf
new file mode 100644
index 0000000000..eb963fe41c
--- /dev/null
+++ b/tests/topotests/isis-snmp/r2/ldpd.conf
@@ -0,0 +1,25 @@
+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-eth0
+ !
+ interface r2-eth1
+ !
+ !
+!
+line vty
+!
diff --git a/tests/topotests/isis-snmp/r2/show_ip_route.ref b/tests/topotests/isis-snmp/r2/show_ip_route.ref
new file mode 100644
index 0000000000..2bcee96064
--- /dev/null
+++ b/tests/topotests/isis-snmp/r2/show_ip_route.ref
@@ -0,0 +1,143 @@
+{
+ "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",
+ "interfaceIndex":3,
+ "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,
+ "interfaceIndex":1,
+ "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",
+ "interfaceIndex":4,
+ "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",
+ "interfaceIndex":3,
+ "interfaceName":"r2-eth1"
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":3,
+ "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",
+ "interfaceIndex":3,
+ "interfaceName":"r2-eth1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.3",
+ "afi":"ipv4",
+ "interfaceIndex":4,
+ "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",
+ "interfaceIndex":4,
+ "interfaceName":"r2-eth2"
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":4,
+ "interfaceName":"r2-eth2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-snmp/r2/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-snmp/r2/show_yang_interface_isis_adjacencies.ref
new file mode 100644
index 0000000000..68a9f4a8a1
--- /dev/null
+++ b/tests/topotests/isis-snmp/r2/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1,42 @@
+{
+ "frr-interface:lib": {
+ "interface": [
+ {
+ "name": "r2-eth0",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0005",
+ "neighbor-extended-circuit-id": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "name": "r2-eth1",
+ "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/isis-snmp/r2/snmpd.conf b/tests/topotests/isis-snmp/r2/snmpd.conf
new file mode 100644
index 0000000000..0f779b8b91
--- /dev/null
+++ b/tests/topotests/isis-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/isis-snmp/r2/zebra.conf b/tests/topotests/isis-snmp/r2/zebra.conf
new file mode 100644
index 0000000000..4aa7440c33
--- /dev/null
+++ b/tests/topotests/isis-snmp/r2/zebra.conf
@@ -0,0 +1,24 @@
+log file zebra.log
+!
+hostname r2
+!
+debug zebra rib detailed
+debug zebra dplane detailed
+debug zebra kernel
+debug zebra nht
+!
+interface lo
+ ip address 2.2.2.2/32
+!
+interface r2-eth0
+ description to rt5
+ ip address 25.0.0.2/24
+!
+interface r2-eth1
+ description to rt3
+ ip address 23.0.0.2/24
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-snmp/r3/isisd.conf b/tests/topotests/isis-snmp/r3/isisd.conf
new file mode 100644
index 0000000000..e06fe8c1f9
--- /dev/null
+++ b/tests/topotests/isis-snmp/r3/isisd.conf
@@ -0,0 +1,25 @@
+hostname r3
+log file isisd.log
+debug isis adj-packets
+debug isis events
+debug isis update-packets
+agentx
+!
+router isis 1
+ 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
+!
+interface r3-eth1
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis circuit-type level-1
+!
+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/isis-snmp/r3/ldpd.conf b/tests/topotests/isis-snmp/r3/ldpd.conf
new file mode 100644
index 0000000000..2935caf13b
--- /dev/null
+++ b/tests/topotests/isis-snmp/r3/ldpd.conf
@@ -0,0 +1,25 @@
+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
+!
diff --git a/tests/topotests/isis-snmp/r3/show_ip_route.ref b/tests/topotests/isis-snmp/r3/show_ip_route.ref
new file mode 100644
index 0000000000..da46f1dfe2
--- /dev/null
+++ b/tests/topotests/isis-snmp/r3/show_ip_route.ref
@@ -0,0 +1,143 @@
+{
+ "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",
+ "interfaceIndex":3,
+ "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",
+ "interfaceIndex":4,
+ "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,
+ "interfaceIndex":1,
+ "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",
+ "interfaceIndex":3,
+ "interfaceName":"r3-eth1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceIndex":4,
+ "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",
+ "interfaceIndex":3,
+ "interfaceName":"r3-eth1"
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":3,
+ "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",
+ "interfaceIndex":4,
+ "interfaceName":"r3-eth2"
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":4,
+ "interfaceName":"r3-eth2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-snmp/r3/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-snmp/r3/show_yang_interface_isis_adjacencies.ref
new file mode 100644
index 0000000000..0922192361
--- /dev/null
+++ b/tests/topotests/isis-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/isis-snmp/r3/snmpd.conf b/tests/topotests/isis-snmp/r3/snmpd.conf
new file mode 100644
index 0000000000..3f3501a6fd
--- /dev/null
+++ b/tests/topotests/isis-snmp/r3/snmpd.conf
@@ -0,0 +1,15 @@
+agentAddress udp:3.3.3.3:161
+
+com2sec public 3.3.3.3 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/isis-snmp/r3/zebra.conf b/tests/topotests/isis-snmp/r3/zebra.conf
new file mode 100644
index 0000000000..6b76114d4d
--- /dev/null
+++ b/tests/topotests/isis-snmp/r3/zebra.conf
@@ -0,0 +1,28 @@
+log file zebra.log
+!
+hostname r3
+!
+debug zebra rib detailed
+debug zebra dplane detailed
+debug zebra kernel
+debug zebra nht
+!
+interface lo
+ ip address 3.3.3.3/32
+!
+interface r3-eth0
+ description to ce3
+ ip address 172.16.1.3/24
+!
+interface r3-eth1
+ description to rt2
+ ip address 13.0.0.3/24
+!
+interface r3-eth2
+ description to rt1
+ ip address 23.0.0.3/24
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-snmp/r4/isisd.conf b/tests/topotests/isis-snmp/r4/isisd.conf
new file mode 100644
index 0000000000..1256141da9
--- /dev/null
+++ b/tests/topotests/isis-snmp/r4/isisd.conf
@@ -0,0 +1,24 @@
+hostname r4
+log file isisd.log
+debug isis adj-packets
+debug isis events
+debug isis update-packets
+agentx
+!
+router isis 1
+ net 10.0000.0000.0000.0000.0000.0000.0000.0000.0004.00
+ metric-style wide
+ redistribute ipv4 connected level-1
+ redistribute ipv6 connected level-1
+!
+interface r4-eth0
+ ip router isis 1
+ ipv6 router isis 1
+ isis circuit-type level-1
+!
+interface r4-eth1
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis circuit-type level-1
+!
diff --git a/tests/topotests/isis-snmp/r4/ldpd.conf b/tests/topotests/isis-snmp/r4/ldpd.conf
new file mode 100644
index 0000000000..b27952514b
--- /dev/null
+++ b/tests/topotests/isis-snmp/r4/ldpd.conf
@@ -0,0 +1,25 @@
+hostname r4
+log file ldpd.log
+!
+debug mpls ldp zebra
+debug mpls ldp event
+debug mpls ldp errors
+debug mpls ldp sync
+!
+mpls ldp
+ router-id 4.4.4.4
+ !
+ address-family ipv4
+ discovery transport-address 4.4.4.4
+ label local allocate host-routes
+ !
+ ttl-security disable
+ !
+ interface r4-eth0
+ !
+ interface r4-eth1
+ !
+ !
+!
+line vty
+!
diff --git a/tests/topotests/isis-snmp/r4/show_ip_route.ref b/tests/topotests/isis-snmp/r4/show_ip_route.ref
new file mode 100644
index 0000000000..da46f1dfe2
--- /dev/null
+++ b/tests/topotests/isis-snmp/r4/show_ip_route.ref
@@ -0,0 +1,143 @@
+{
+ "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",
+ "interfaceIndex":3,
+ "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",
+ "interfaceIndex":4,
+ "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,
+ "interfaceIndex":1,
+ "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",
+ "interfaceIndex":3,
+ "interfaceName":"r3-eth1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceIndex":4,
+ "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",
+ "interfaceIndex":3,
+ "interfaceName":"r3-eth1"
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":3,
+ "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",
+ "interfaceIndex":4,
+ "interfaceName":"r3-eth2"
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":4,
+ "interfaceName":"r3-eth2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-snmp/r4/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-snmp/r4/show_yang_interface_isis_adjacencies.ref
new file mode 100644
index 0000000000..38562e39e7
--- /dev/null
+++ b/tests/topotests/isis-snmp/r4/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1,42 @@
+{
+ "frr-interface:lib": {
+ "interface": [
+ {
+ "name": "r4-eth0",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0001",
+ "neighbor-extended-circuit-id": 2,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "name": "r4-eth1",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0005",
+ "neighbor-extended-circuit-id": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-snmp/r4/snmpd.conf b/tests/topotests/isis-snmp/r4/snmpd.conf
new file mode 100644
index 0000000000..e5e336d888
--- /dev/null
+++ b/tests/topotests/isis-snmp/r4/snmpd.conf
@@ -0,0 +1,15 @@
+agentAddress udp:4.4.4.4:161
+
+com2sec public 4.4.4.4 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/isis-snmp/r4/zebra.conf b/tests/topotests/isis-snmp/r4/zebra.conf
new file mode 100644
index 0000000000..fa13601164
--- /dev/null
+++ b/tests/topotests/isis-snmp/r4/zebra.conf
@@ -0,0 +1,24 @@
+log file zebra.log
+!
+hostname r4
+!
+debug zebra rib detailed
+debug zebra dplane detailed
+debug zebra kernel
+debug zebra nht
+!
+interface lo
+ ip address 4.4.4.4/32
+!
+interface r4-eth0
+ description to rt1
+ ip address 14.0.0.4/24
+!
+interface r4-eth1
+ description to rt5
+ ip address 45.0.0.4/24
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-snmp/r5/isisd.conf b/tests/topotests/isis-snmp/r5/isisd.conf
new file mode 100644
index 0000000000..58859041a9
--- /dev/null
+++ b/tests/topotests/isis-snmp/r5/isisd.conf
@@ -0,0 +1,25 @@
+hostname r5
+log file isisd.log
+debug isis adj-packets
+debug isis events
+debug isis update-packets
+agentx
+!
+router isis 1
+ net 10.0000.0000.0000.0000.0000.0000.0000.0000.0005.00
+ metric-style wide
+ redistribute ipv4 connected level-1
+ redistribute ipv6 connected level-1
+!
+interface r5-eth0
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis circuit-type level-1
+!
+interface r5-eth1
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis circuit-type level-1
+!
diff --git a/tests/topotests/isis-snmp/r5/ldpd.conf b/tests/topotests/isis-snmp/r5/ldpd.conf
new file mode 100644
index 0000000000..f3ba867a9f
--- /dev/null
+++ b/tests/topotests/isis-snmp/r5/ldpd.conf
@@ -0,0 +1,25 @@
+hostname r5
+log file ldpd.log
+!
+debug mpls ldp zebra
+debug mpls ldp event
+debug mpls ldp errors
+debug mpls ldp sync
+!
+mpls ldp
+ router-id 5.5.5.5
+ !
+ address-family ipv4
+ discovery transport-address 5.5.5.5
+ label local allocate host-routes
+ !
+ ttl-security disable
+ !
+ interface r5-eth0
+ !
+ interface r5-eth1
+ !
+ !
+!
+line vty
+!
diff --git a/tests/topotests/isis-snmp/r5/ldpdconf b/tests/topotests/isis-snmp/r5/ldpdconf
new file mode 100644
index 0000000000..fc700608b5
--- /dev/null
+++ b/tests/topotests/isis-snmp/r5/ldpdconf
@@ -0,0 +1,25 @@
+hostname r5
+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 5.5.5.5
+ label local allocate host-routes
+ !
+ ttl-security disable
+ !
+ interface r5-eth0
+ !
+ interface r5-eth1
+ !
+ !
+!
+line vty
+!
diff --git a/tests/topotests/isis-snmp/r5/show_ip_route.ref b/tests/topotests/isis-snmp/r5/show_ip_route.ref
new file mode 100644
index 0000000000..da46f1dfe2
--- /dev/null
+++ b/tests/topotests/isis-snmp/r5/show_ip_route.ref
@@ -0,0 +1,143 @@
+{
+ "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",
+ "interfaceIndex":3,
+ "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",
+ "interfaceIndex":4,
+ "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,
+ "interfaceIndex":1,
+ "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",
+ "interfaceIndex":3,
+ "interfaceName":"r3-eth1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceIndex":4,
+ "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",
+ "interfaceIndex":3,
+ "interfaceName":"r3-eth1"
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":3,
+ "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",
+ "interfaceIndex":4,
+ "interfaceName":"r3-eth2"
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":4,
+ "interfaceName":"r3-eth2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-snmp/r5/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-snmp/r5/show_yang_interface_isis_adjacencies.ref
new file mode 100644
index 0000000000..c009f53ef6
--- /dev/null
+++ b/tests/topotests/isis-snmp/r5/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1,42 @@
+{
+ "frr-interface:lib": {
+ "interface": [
+ {
+ "name": "r5-eth0",
+ "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": "r5-eth1",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0004",
+ "neighbor-extended-circuit-id": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-snmp/r5/snmpd.conf b/tests/topotests/isis-snmp/r5/snmpd.conf
new file mode 100644
index 0000000000..5bebbdebd4
--- /dev/null
+++ b/tests/topotests/isis-snmp/r5/snmpd.conf
@@ -0,0 +1,15 @@
+agentAddress udp:5.5.5.5:161
+
+com2sec public 5.5.5.5 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/isis-snmp/r5/zebra.conf b/tests/topotests/isis-snmp/r5/zebra.conf
new file mode 100644
index 0000000000..7230129f22
--- /dev/null
+++ b/tests/topotests/isis-snmp/r5/zebra.conf
@@ -0,0 +1,24 @@
+log file zebra.log
+!
+hostname r5
+!
+debug zebra rib detailed
+debug zebra dplane detailed
+debug zebra kernel
+debug zebra nht
+!
+interface lo
+ ip address 5.5.5.5/32
+!
+interface r5-eth0
+ description to rt2
+ ip address 25.0.0.5/24
+!
+interface r5-eth1
+ description to rt4
+ ip address 45.0.0.5/24
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-snmp/test_isis_snmp.dot b/tests/topotests/isis-snmp/test_isis_snmp.dot
new file mode 100644
index 0000000000..6d8c893712
--- /dev/null
+++ b/tests/topotests/isis-snmp/test_isis_snmp.dot
@@ -0,0 +1,114 @@
+## Color coding:
+#########################
+## Main FRR: #f08080 red
+## Switches: #d0e0d0 gray
+## RIP: #19e3d9 Cyan
+## RIPng: #fcb314 dark yellow
+## OSPFv2: #32b835 Green
+## OSPFv3: #19e3d9 Cyan
+## ISIS IPv4 #fcb314 dark yellow
+## ISIS IPv6 #9a81ec purple
+## BGP IPv4 #eee3d3 beige
+## BGP IPv6 #fdff00 yellow
+##### Colors (see http://www.color-hex.com/)
+
+graph template {
+ label="Test Topology - LDP-VPLS 1";
+
+ # Routers
+ ce3 [
+ shape=doubleoctagon
+ label="ce3",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r1 [
+ shape=doubleoctagon,
+ label="r1",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r2 [
+ shape=doubleoctagon
+ label="r2",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r3 [
+ shape=doubleoctagon
+ label="r3",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+
+ r4 [
+ shape=doubleoctagon
+ label="r4",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r5 [
+ shape=doubleoctagon
+ label="r5",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+
+
+
+ # Switches
+ s1 [
+ shape=oval,
+ label="s1\n14.0.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ s2 [
+ shape=oval,
+ label="s2\n25.0.0.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ s3 [
+ shape=oval,
+ label="s3\n172.16.1.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ s4 [
+ shape=oval,
+ label="s4\n45.0.0.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ s5 [
+ shape=oval,
+ label="s5\n13.0.0.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ s6 [
+ shape=oval,
+ label="s6\n23.0.0.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+
+ # Connections
+ ce3 -- s3 [label="eth0\n.3"];
+
+ r1 -- s1 [label="eth1\n.1"];
+ r1 -- s5 [label="eth2\n.1"];
+
+ r2 -- s2 [label="eth1\n.2"];
+ r2 -- s6 [label="eth2\n.2"];
+
+ r3 -- s5 [label="eth1\n.3"];
+ r3 -- s6 [label="eth2\n.3"];
+
+ r4 -- s1 [label="eth1\n.4"];
+ r4 -- s4 [label="eth2\n.4"];
+
+ r5 -- s2 [label="eth1\n.5"];
+ r5 -- s4 [label="eth2\n.5"];
+}
diff --git a/tests/topotests/isis-snmp/test_isis_snmp.py b/tests/topotests/isis-snmp/test_isis_snmp.py
new file mode 100755
index 0000000000..fe411aa8fd
--- /dev/null
+++ b/tests/topotests/isis-snmp/test_isis_snmp.py
@@ -0,0 +1,373 @@
+#!/usr/bin/env python
+
+#
+# test_isis_snmp.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_isis_snmp.py:
+
+ +---------+ 45.0.0.0/24 +---------+
+ | | rt4-eth1 | |
+ | RT4 +----------------+ RT5 |
+ | | rt5-eth1| |
+ +---------+ +---------+
+ rt4-eth0| |rt5-eth0
+ | |
+ 14.0.0.0/24| |25.0.0.0/24
+ | |
+ rt1-eth0| |rt2-eth0
+ +---------+ +---------+
+ | | | |
+ | RT1 | | RT2 |
+ | 1.1.1.1 | | 2.2.2.2 |
+ | | | |
+ +---------+ +---------+
+ rt1-eth1| |rt2-eth1
+ | |
+ | |
+ 13.0.0.0/24| +---------+ |23.0.0.0/24
+ | | | |
+ | | RT3 | |
+ +--------+ 3.3.3.3 +-------+
+ rt3-eth1| |rt3-eth2
+ +---------+
+ |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 ["ce3", "r1", "r2", "r3", "r4", "r5"]:
+ tgen.add_router(router)
+
+ #
+ # Define connections
+ #
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r4"])
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["r5"])
+ 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["r4"])
+ switch.add_link(tgen.gears["r5"])
+
+ 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"
+
+ # skip tests is SNMP not installed
+ if not os.path.isfile("/usr/sbin/snmpd"):
+ error_msg = "SNMP not installed - skipping"
+ pytest.skip(error_msg)
+
+ # This function initiates the topology build with Topogen...
+ tgen = Topogen(TemplateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ # For all registered routers, load the zebra configuration file
+ for rname, router in router_list.iteritems():
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ # Don't start the following in the CE nodes
+ if router.name[0] == "r":
+ router.load_config(
+ TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname)),
+ "-M snmp",
+ )
+ router.load_config(
+ TopoRouter.RD_LDP, os.path.join(CWD, "{}/ldpd.conf".format(rname)),
+ )
+ router.load_config(
+ TopoRouter.RD_SNMP, os.path.join(CWD, "{}/snmpd.conf".format(rname)),
+ "-Le -Ivacm_conf,usmConf,iquery -V -DAgentX,trap",
+ )
+
+ # After loading the configurations, this function loads configured daemons.
+ 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. Wait at most 80 seconds.
+ test_func = partial(topotest.router_json_cmp, tgen.gears[rname], command, expected)
+ _, diff = topotest.run_and_expect(test_func, None, count=160, wait=0.5)
+ assertmsg = '"{}" JSON output mismatches the expected result'.format(rname)
+ assert diff is None, assertmsg
+
+def generate_oid(numoids, index1, index2):
+ if numoids == 1:
+ oid = "{}".format(index1)
+ else:
+ oid = "{}.{}".format(index1, index2)
+ return oid
+
+
+def test_isis_convergence():
+ logger.info("Test: check ISIS adjacencies")
+ tgen = get_topogen()
+
+ for rname in ["r1", "r2", "r3", "r4", "r5"]:
+ router_compare_json_output(
+ rname,
+ "show yang operational-data /frr-interface:lib isisd",
+ "show_yang_interface_isis_adjacencies.ref")
+
+def test_r1_scalar_snmp():
+ "Wait for protocol convergence"
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.net.get("r1")
+ r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c")
+
+ assert r1_snmp.test_oid('isisSysVersion', "one(1)")
+ assert r1_snmp.test_oid('isisSysLevelType', "level1and2(3)")
+ assert r1_snmp.test_oid('isisSysID',"00 00 00 00 00 01")
+ assert r1_snmp.test_oid('isisSysMaxPathSplits',"32")
+ assert r1_snmp.test_oid('isisSysMaxLSPGenInt',"900 seconds")
+ assert r1_snmp.test_oid('isisSysAdminState',"on(1)")
+ assert r1_snmp.test_oid('isisSysMaxAge',"1200 seconds")
+ assert r1_snmp.test_oid('isisSysProtSupported',"07 5 6 7")
+
+ r2 = tgen.net.get("r2")
+ r2_snmp = SnmpTester(r2, "2.2.2.2", "public", "2c")
+
+ assert r2_snmp.test_oid('isisSysVersion', "one(1)")
+ assert r2_snmp.test_oid('isisSysLevelType', "level1and2(3)")
+ assert r2_snmp.test_oid('isisSysID',"00 00 00 00 00 02")
+ assert r2_snmp.test_oid('isisSysMaxPathSplits',"32")
+ assert r2_snmp.test_oid('isisSysMaxLSPGenInt',"900 seconds")
+ assert r2_snmp.test_oid('isisSysAdminState',"on(1)")
+ assert r2_snmp.test_oid('isisSysMaxAge',"1200 seconds")
+ assert r2_snmp.test_oid('isisSysProtSupported',"07 5 6 7")
+
+
+circtable_test = {
+ "isisCircIfIndex": ["2", "3", "1"],
+ "isisCircAdminState": ["on(1)", "on(1)", "on(1)"],
+ "isisCircExistState": ["active(1)", "active(1)", "active(1)"],
+ "isisCircType": ["broadcast(1)", "ptToPt(2)", "staticIn(3)"],
+ "isisCircExtDomain": ["false(2)", "false(2)", "false(2)"],
+ "isisCircLevelType": ["level1(1)", "level1(1)", "level1and2(3)"],
+ "isisCircPassiveCircuit": ["false(2)", "false(2)", "true(1)"],
+ "isisCircMeshGroupEnabled": ["inactive(1)", "inactive(1)", "inactive(1)"],
+ "isisCircSmallHellos": ["false(2)", "false(2)", "false(2)"],
+ "isisCirc3WayEnabled": ["false(2)", "false(2)", "false(2)"],
+ }
+
+def test_r1_isisCircTable():
+ tgen = get_topogen()
+
+ r1 = tgen.net.get("r1")
+ r1r = tgen.gears["r1"]
+
+ r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c")
+
+ oids = []
+ oids.append(generate_oid(1,1,0))
+ oids.append(generate_oid(1,2,0))
+ oids.append(generate_oid(1,3,0))
+
+ # check items
+ for item in circtable_test.keys():
+ assertmsg = "{} should be {} oids {} full dict {}:".format(
+ item, circtable_test[item], oids, r1_snmp.walk(item)
+ )
+ assert r1_snmp.test_oid_walk(item, circtable_test[item], oids), assertmsg
+
+circleveltable_test = {
+ "isisCircLevelMetric": ["10", "10", "10", "10"],
+ "isisCircLevelWideMetric": ["10", "10", "0", "0"],
+ "isisCircLevelISPriority": ["64", "64", "64", "64"],
+ "isisCircLevelIDOctet": ["2", "0", "0", "0"],
+ "isisCircLevelHelloMultiplier": ["10", "10", "10", "10"],
+ "isisCircLevelHelloTimer": ["3000 milliseconds", "3000 milliseconds", "3000 milliseconds", "3000 milliseconds"],
+ "isisCircLevelMinLSPRetransInt": ["1 seconds", "1 seconds", "0 seconds", "0 seconds"],
+ }
+
+def test_r1_isislevelCircTable():
+ tgen = get_topogen()
+
+ r1 = tgen.net.get("r1")
+ r1r = tgen.gears["r1"]
+
+ r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c")
+
+ oids = []
+ oids.append(generate_oid(2,1,"area"))
+ oids.append(generate_oid(2,2,"area"))
+ oids.append(generate_oid(2,3,"area"))
+ oids.append(generate_oid(2,3,"domain"))
+
+ # check items
+ for item in circleveltable_test.keys():
+ assertmsg = "{} should be {} oids {} full dict {}:".format(
+ item, circleveltable_test[item], oids, r1_snmp.walk(item)
+ )
+ assert r1_snmp.test_oid_walk(item, circleveltable_test[item], oids), assertmsg
+
+
+adjtable_test = {
+ "isisISAdjState": ["up(3)", "up(3)"],
+ "isisISAdj3WayState": ["down(2)", "up(0)"],
+ "isisISAdjNeighSysType": ["l1IntermediateSystem(1)", "l1IntermediateSystem(1)"],
+ "isisISAdjNeighSysID": ["00 00 00 00 00 04", "00 00 00 00 00 03"],
+ "isisISAdjNbrExtendedCircID": ["0", "0"],
+ "isisISAdjUsage": ["0", "level1(1)"],
+ "isisISAdjNeighPriority": ["64", "0"],
+}
+
+adjtable_down_test = {
+ "isisISAdjState": ["up(3)"],
+ "isisISAdj3WayState": ["down(2)"],
+ "isisISAdjNeighSysType": ["l1IntermediateSystem(1)"],
+ "isisISAdjNeighSysID": ["00 00 00 00 00 04"],
+ "isisISAdjNbrExtendedCircID": ["0"],
+ "isisISAdjUsage": ["0"],
+ "isisISAdjNeighPriority": ["64"],
+}
+
+def test_r1_isisAdjTable():
+ "check ISIS Adjacency Table"
+ tgen = get_topogen()
+ r1 = tgen.net.get("r1")
+ r1_cmd = tgen.gears["r1"]
+ r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c")
+
+ oids = []
+ oids.append(generate_oid(2,1,1))
+ oids.append(generate_oid(2,2,1))
+
+ oids_down = []
+ oids_down.append(generate_oid(2,1,1))
+
+ # check items
+ for item in adjtable_test.keys():
+ assertmsg = "{} should be {} oids {} full dict {}:".format(
+ item, adjtable_test[item], oids, r1_snmp.walk(item)
+ )
+ assert r1_snmp.test_oid_walk(item, adjtable_test[item], oids), assertmsg
+
+
+ # shutdown interface and one adjacency should be removed
+ "check ISIS adjacency is removed when interface is shutdown"
+ r1_cmd.vtysh_cmd("conf t\ninterface r1-eth1\nshutdown")
+ r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c")
+
+ for item in adjtable_down_test.keys():
+ assertmsg = "{} should be {} oids {} full dict {}:".format(
+ item, adjtable_down_test[item], oids_down, r1_snmp.walk(item)
+ )
+ assert r1_snmp.test_oid_walk(item, adjtable_down_test[item], oids_down), assertmsg
+
+ # no shutdown interface and adjacency should be restored
+ r1_cmd.vtysh_cmd("conf t\ninterface r1-eth1\nno shutdown")
+
+
+# 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))
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))
diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in
index 53067c43f4..81c9770e55 100755
--- a/vtysh/extract.pl.in
+++ b/vtysh/extract.pl.in
@@ -107,7 +107,7 @@ sub scan_file {
$protocol = "VTYSH_ALL";
}
elsif ($file =~ /lib\/agentx\.c$/) {
- $protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA";
+ $protocol = "VTYSH_ISISD|VTYSH_RIPD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA";
}
elsif ($file =~ /lib\/nexthop_group\.c$/) {
$protocol = "VTYSH_NH_GROUP";
diff --git a/yang/frr-bfdd.yang b/yang/frr-bfdd.yang
index 5b434162d0..0f090a1b72 100644
--- a/yang/frr-bfdd.yang
+++ b/yang/frr-bfdd.yang
@@ -185,7 +185,7 @@ module frr-bfdd {
leaf administrative-down {
type boolean;
- default true;
+ default false;
description "Disables or enables the session administratively";
}