summaryrefslogtreecommitdiffstats
path: root/ospf6d/ospf6_neighbor.c
diff options
context:
space:
mode:
Diffstat (limited to 'ospf6d/ospf6_neighbor.c')
-rw-r--r--ospf6d/ospf6_neighbor.c1327
1 files changed, 1327 insertions, 0 deletions
diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c
new file mode 100644
index 0000000..e1aec06
--- /dev/null
+++ b/ospf6d/ospf6_neighbor.c
@@ -0,0 +1,1327 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2003 Yasuhiro Ohara
+ */
+
+#include <zebra.h>
+
+#include "log.h"
+#include "memory.h"
+#include "frrevent.h"
+#include "linklist.h"
+#include "vty.h"
+#include "command.h"
+#include "lib/bfd.h"
+
+#include "ospf6_proto.h"
+#include "ospf6_lsa.h"
+#include "ospf6_lsdb.h"
+#include "ospf6_message.h"
+#include "ospf6_top.h"
+#include "ospf6_area.h"
+#include "ospf6_interface.h"
+#include "ospf6_neighbor.h"
+#include "ospf6_intra.h"
+#include "ospf6_flood.h"
+#include "ospf6d.h"
+#include "ospf6_bfd.h"
+#include "ospf6_abr.h"
+#include "ospf6_asbr.h"
+#include "ospf6_lsa.h"
+#include "ospf6_spf.h"
+#include "ospf6_zebra.h"
+#include "ospf6_gr.h"
+#include "lib/json.h"
+
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_NEIGHBOR, "OSPF6 neighbor");
+
+DEFINE_HOOK(ospf6_neighbor_change,
+ (struct ospf6_neighbor * on, int state, int next_state),
+ (on, state, next_state));
+
+unsigned char conf_debug_ospf6_neighbor = 0;
+
+const char *const ospf6_neighbor_state_str[] = {
+ "None", "Down", "Attempt", "Init", "Twoway",
+ "ExStart", "ExChange", "Loading", "Full", NULL};
+
+const char *const ospf6_neighbor_event_str[] = {
+ "NoEvent", "HelloReceived", "2-WayReceived", "NegotiationDone",
+ "ExchangeDone", "LoadingDone", "AdjOK?", "SeqNumberMismatch",
+ "BadLSReq", "1-WayReceived", "InactivityTimer",
+};
+
+int ospf6_neighbor_cmp(void *va, void *vb)
+{
+ struct ospf6_neighbor *ona = (struct ospf6_neighbor *)va;
+ struct ospf6_neighbor *onb = (struct ospf6_neighbor *)vb;
+
+ if (ona->router_id == onb->router_id)
+ return 0;
+
+ return (ntohl(ona->router_id) < ntohl(onb->router_id)) ? -1 : 1;
+}
+
+struct ospf6_neighbor *ospf6_neighbor_lookup(uint32_t router_id,
+ struct ospf6_interface *oi)
+{
+ struct listnode *n;
+ struct ospf6_neighbor *on;
+
+ for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, n, on))
+ if (on->router_id == router_id)
+ return on;
+
+ return (struct ospf6_neighbor *)NULL;
+}
+
+struct ospf6_neighbor *ospf6_area_neighbor_lookup(struct ospf6_area *area,
+ uint32_t router_id)
+{
+ struct ospf6_interface *oi;
+ struct ospf6_neighbor *nbr;
+ struct listnode *node;
+
+ for (ALL_LIST_ELEMENTS_RO(area->if_list, node, oi)) {
+ nbr = ospf6_neighbor_lookup(router_id, oi);
+ if (nbr)
+ return nbr;
+ }
+
+ return NULL;
+}
+
+static void ospf6_neighbor_clear_ls_lists(struct ospf6_neighbor *on)
+{
+ struct ospf6_lsa *lsa;
+ struct ospf6_lsa *lsanext;
+
+ ospf6_lsdb_remove_all(on->summary_list);
+ if (on->last_ls_req) {
+ ospf6_lsa_unlock(&on->last_ls_req);
+ on->last_ls_req = NULL;
+ }
+
+ ospf6_lsdb_remove_all(on->request_list);
+ for (ALL_LSDB(on->retrans_list, lsa, lsanext)) {
+ ospf6_decrement_retrans_count(lsa);
+ ospf6_lsdb_remove(lsa, on->retrans_list);
+ }
+}
+
+/* create ospf6_neighbor */
+struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id,
+ struct ospf6_interface *oi)
+{
+ struct ospf6_neighbor *on;
+ char buf[16];
+ int type;
+
+ on = XCALLOC(MTYPE_OSPF6_NEIGHBOR, sizeof(struct ospf6_neighbor));
+ inet_ntop(AF_INET, &router_id, buf, sizeof(buf));
+ snprintf(on->name, sizeof(on->name), "%s%%%s", buf,
+ oi->interface->name);
+ on->ospf6_if = oi;
+ on->state = OSPF6_NEIGHBOR_DOWN;
+ on->state_change = 0;
+ monotime(&on->last_changed);
+ on->router_id = router_id;
+
+ on->summary_list = ospf6_lsdb_create(on);
+ on->request_list = ospf6_lsdb_create(on);
+ on->retrans_list = ospf6_lsdb_create(on);
+
+ on->dbdesc_list = ospf6_lsdb_create(on);
+ on->lsupdate_list = ospf6_lsdb_create(on);
+ on->lsack_list = ospf6_lsdb_create(on);
+
+ for (type = 0; type < OSPF6_MESSAGE_TYPE_MAX; type++) {
+ on->seqnum_l[type] = 0;
+ on->seqnum_h[type] = 0;
+ }
+
+ on->auth_present = false;
+
+ listnode_add_sort(oi->neighbor_list, on);
+
+ ospf6_bfd_info_nbr_create(oi, on);
+ return on;
+}
+
+void ospf6_neighbor_delete(struct ospf6_neighbor *on)
+{
+ ospf6_neighbor_clear_ls_lists(on);
+
+ ospf6_lsdb_remove_all(on->dbdesc_list);
+ ospf6_lsdb_remove_all(on->lsupdate_list);
+ ospf6_lsdb_remove_all(on->lsack_list);
+
+ ospf6_lsdb_delete(on->summary_list);
+ ospf6_lsdb_delete(on->request_list);
+ ospf6_lsdb_delete(on->retrans_list);
+
+ ospf6_lsdb_delete(on->dbdesc_list);
+ ospf6_lsdb_delete(on->lsupdate_list);
+ ospf6_lsdb_delete(on->lsack_list);
+
+ EVENT_OFF(on->inactivity_timer);
+
+ EVENT_OFF(on->last_dbdesc_release_timer);
+
+ EVENT_OFF(on->thread_send_dbdesc);
+ EVENT_OFF(on->thread_send_lsreq);
+ EVENT_OFF(on->thread_send_lsupdate);
+ EVENT_OFF(on->thread_send_lsack);
+ EVENT_OFF(on->thread_exchange_done);
+ EVENT_OFF(on->thread_adj_ok);
+ EVENT_OFF(on->event_loading_done);
+
+ EVENT_OFF(on->gr_helper_info.t_grace_timer);
+
+ bfd_sess_free(&on->bfd_session);
+ XFREE(MTYPE_OSPF6_NEIGHBOR, on);
+}
+
+static void ospf6_neighbor_state_change(uint8_t next_state,
+ struct ospf6_neighbor *on, int event)
+{
+ uint8_t prev_state;
+
+ prev_state = on->state;
+ on->state = next_state;
+
+ if (prev_state == next_state)
+ return;
+
+ on->state_change++;
+ monotime(&on->last_changed);
+
+ /* log */
+ if (IS_OSPF6_DEBUG_NEIGHBOR(STATE)) {
+ zlog_debug(
+ "Neighbor state change %s (Router-ID: %pI4): [%s]->[%s] (%s)",
+ on->name, &on->router_id,
+ ospf6_neighbor_state_str[prev_state],
+ ospf6_neighbor_state_str[next_state],
+ ospf6_neighbor_event_string(event));
+ }
+
+ /* Optionally notify about adjacency changes */
+ if (CHECK_FLAG(on->ospf6_if->area->ospf6->config_flags,
+ OSPF6_LOG_ADJACENCY_CHANGES)
+ && (CHECK_FLAG(on->ospf6_if->area->ospf6->config_flags,
+ OSPF6_LOG_ADJACENCY_DETAIL)
+ || (next_state == OSPF6_NEIGHBOR_FULL)
+ || (next_state < prev_state)))
+ zlog_notice(
+ "AdjChg: Nbr %pI4(%s) on %s: %s -> %s (%s)",
+ &on->router_id,
+ vrf_id_to_name(on->ospf6_if->interface->vrf->vrf_id),
+ on->name, ospf6_neighbor_state_str[prev_state],
+ ospf6_neighbor_state_str[next_state],
+ ospf6_neighbor_event_string(event));
+
+ if (prev_state == OSPF6_NEIGHBOR_FULL
+ || next_state == OSPF6_NEIGHBOR_FULL) {
+ if (!OSPF6_GR_IS_ACTIVE_HELPER(on)) {
+ OSPF6_ROUTER_LSA_SCHEDULE(on->ospf6_if->area);
+ if (on->ospf6_if->state == OSPF6_INTERFACE_DR) {
+ OSPF6_NETWORK_LSA_SCHEDULE(on->ospf6_if);
+ OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT(
+ on->ospf6_if);
+ }
+ }
+ if (next_state == OSPF6_NEIGHBOR_FULL)
+ on->ospf6_if->area->intra_prefix_originate = 1;
+
+ if (!OSPF6_GR_IS_ACTIVE_HELPER(on))
+ OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(
+ on->ospf6_if->area);
+
+ if ((prev_state == OSPF6_NEIGHBOR_LOADING
+ || prev_state == OSPF6_NEIGHBOR_EXCHANGE)
+ && next_state == OSPF6_NEIGHBOR_FULL) {
+ OSPF6_AS_EXTERN_LSA_SCHEDULE(on->ospf6_if);
+ on->ospf6_if->area->full_nbrs++;
+ }
+
+ if (prev_state == OSPF6_NEIGHBOR_FULL)
+ on->ospf6_if->area->full_nbrs--;
+ }
+
+ if ((prev_state == OSPF6_NEIGHBOR_EXCHANGE
+ || prev_state == OSPF6_NEIGHBOR_LOADING)
+ && (next_state != OSPF6_NEIGHBOR_EXCHANGE
+ && next_state != OSPF6_NEIGHBOR_LOADING))
+ ospf6_maxage_remove(on->ospf6_if->area->ospf6);
+
+ hook_call(ospf6_neighbor_change, on, next_state, prev_state);
+ ospf6_bfd_trigger_event(on, prev_state, next_state);
+}
+
+/* RFC2328 section 10.4 */
+static int need_adjacency(struct ospf6_neighbor *on)
+{
+ if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT
+ || on->ospf6_if->state == OSPF6_INTERFACE_DR
+ || on->ospf6_if->state == OSPF6_INTERFACE_BDR)
+ return 1;
+
+ if (on->ospf6_if->drouter == on->router_id
+ || on->ospf6_if->bdrouter == on->router_id)
+ return 1;
+
+ return 0;
+}
+
+void hello_received(struct event *thread)
+{
+ struct ospf6_neighbor *on;
+
+ on = (struct ospf6_neighbor *)EVENT_ARG(thread);
+ assert(on);
+
+ if (IS_OSPF6_DEBUG_NEIGHBOR(EVENT))
+ zlog_debug("Neighbor Event %s: *HelloReceived*", on->name);
+
+ /* reset Inactivity Timer */
+ EVENT_OFF(on->inactivity_timer);
+ event_add_timer(master, inactivity_timer, on,
+ on->ospf6_if->dead_interval, &on->inactivity_timer);
+
+ if (on->state <= OSPF6_NEIGHBOR_DOWN)
+ ospf6_neighbor_state_change(OSPF6_NEIGHBOR_INIT, on,
+ OSPF6_NEIGHBOR_EVENT_HELLO_RCVD);
+}
+
+void twoway_received(struct event *thread)
+{
+ struct ospf6_neighbor *on;
+
+ on = (struct ospf6_neighbor *)EVENT_ARG(thread);
+ assert(on);
+
+ if (on->state > OSPF6_NEIGHBOR_INIT)
+ return;
+
+ if (IS_OSPF6_DEBUG_NEIGHBOR(EVENT))
+ zlog_debug("Neighbor Event %s: *2Way-Received*", on->name);
+
+ event_add_event(master, neighbor_change, on->ospf6_if, 0, NULL);
+
+ if (!need_adjacency(on)) {
+ ospf6_neighbor_state_change(OSPF6_NEIGHBOR_TWOWAY, on,
+ OSPF6_NEIGHBOR_EVENT_TWOWAY_RCVD);
+ return;
+ }
+
+ ospf6_neighbor_state_change(OSPF6_NEIGHBOR_EXSTART, on,
+ OSPF6_NEIGHBOR_EVENT_TWOWAY_RCVD);
+ SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT);
+ SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT);
+ SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT);
+
+ EVENT_OFF(on->thread_send_dbdesc);
+ event_add_event(master, ospf6_dbdesc_send, on, 0,
+ &on->thread_send_dbdesc);
+}
+
+void negotiation_done(struct event *thread)
+{
+ struct ospf6_neighbor *on;
+ struct ospf6_lsa *lsa, *lsanext;
+
+ on = (struct ospf6_neighbor *)EVENT_ARG(thread);
+ assert(on);
+
+ if (on->state != OSPF6_NEIGHBOR_EXSTART)
+ return;
+
+ if (IS_OSPF6_DEBUG_NEIGHBOR(EVENT))
+ zlog_debug("Neighbor Event %s: *NegotiationDone*", on->name);
+
+ /* clear ls-list */
+ ospf6_neighbor_clear_ls_lists(on);
+
+ /* Interface scoped LSAs */
+ for (ALL_LSDB(on->ospf6_if->lsdb, lsa, lsanext)) {
+ if (OSPF6_LSA_IS_MAXAGE(lsa)) {
+ ospf6_increment_retrans_count(lsa);
+ ospf6_lsdb_add(ospf6_lsa_copy(lsa), on->retrans_list);
+ } else
+ ospf6_lsdb_add(ospf6_lsa_copy(lsa), on->summary_list);
+ }
+
+ /* Area scoped LSAs */
+ for (ALL_LSDB(on->ospf6_if->area->lsdb, lsa, lsanext)) {
+ if (OSPF6_LSA_IS_MAXAGE(lsa)) {
+ ospf6_increment_retrans_count(lsa);
+ ospf6_lsdb_add(ospf6_lsa_copy(lsa), on->retrans_list);
+ } else
+ ospf6_lsdb_add(ospf6_lsa_copy(lsa), on->summary_list);
+ }
+
+ /* AS scoped LSAs */
+ for (ALL_LSDB(on->ospf6_if->area->ospf6->lsdb, lsa, lsanext)) {
+ if (OSPF6_LSA_IS_MAXAGE(lsa)) {
+ ospf6_increment_retrans_count(lsa);
+ ospf6_lsdb_add(ospf6_lsa_copy(lsa), on->retrans_list);
+ } else
+ ospf6_lsdb_add(ospf6_lsa_copy(lsa), on->summary_list);
+ }
+
+ UNSET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT);
+ ospf6_neighbor_state_change(OSPF6_NEIGHBOR_EXCHANGE, on,
+ OSPF6_NEIGHBOR_EVENT_NEGOTIATION_DONE);
+}
+
+static void ospf6_neighbor_last_dbdesc_release(struct event *thread)
+{
+ struct ospf6_neighbor *on = EVENT_ARG(thread);
+
+ assert(on);
+ memset(&on->dbdesc_last, 0, sizeof(struct ospf6_dbdesc));
+}
+
+void exchange_done(struct event *thread)
+{
+ struct ospf6_neighbor *on;
+
+ on = (struct ospf6_neighbor *)EVENT_ARG(thread);
+ assert(on);
+
+ if (on->state != OSPF6_NEIGHBOR_EXCHANGE)
+ return;
+
+ if (IS_OSPF6_DEBUG_NEIGHBOR(EVENT))
+ zlog_debug("Neighbor Event %s: *ExchangeDone*", on->name);
+
+ EVENT_OFF(on->thread_send_dbdesc);
+ ospf6_lsdb_remove_all(on->dbdesc_list);
+
+ /* RFC 2328 (10.8): Release the last dbdesc after dead_interval */
+ if (!CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT)) {
+ EVENT_OFF(on->last_dbdesc_release_timer);
+ event_add_timer(master, ospf6_neighbor_last_dbdesc_release, on,
+ on->ospf6_if->dead_interval,
+ &on->last_dbdesc_release_timer);
+ }
+
+ if (on->request_list->count == 0)
+ ospf6_neighbor_state_change(OSPF6_NEIGHBOR_FULL, on,
+ OSPF6_NEIGHBOR_EVENT_EXCHANGE_DONE);
+ else {
+ ospf6_neighbor_state_change(OSPF6_NEIGHBOR_LOADING, on,
+ OSPF6_NEIGHBOR_EVENT_EXCHANGE_DONE);
+
+ event_add_event(master, ospf6_lsreq_send, on, 0,
+ &on->thread_send_lsreq);
+ }
+}
+
+/* Check loading state. */
+void ospf6_check_nbr_loading(struct ospf6_neighbor *on)
+{
+
+ /* RFC2328 Section 10.9: When the neighbor responds to these requests
+ with the proper Link State Update packet(s), the Link state request
+ list is truncated and a new Link State Request packet is sent.
+ */
+ if ((on->state == OSPF6_NEIGHBOR_LOADING)
+ || (on->state == OSPF6_NEIGHBOR_EXCHANGE)) {
+ if (on->request_list->count == 0)
+ event_add_event(master, loading_done, on, 0,
+ &on->event_loading_done);
+ else if (on->last_ls_req == NULL) {
+ EVENT_OFF(on->thread_send_lsreq);
+ event_add_event(master, ospf6_lsreq_send, on, 0,
+ &on->thread_send_lsreq);
+ }
+ }
+}
+
+void loading_done(struct event *thread)
+{
+ struct ospf6_neighbor *on;
+
+ on = (struct ospf6_neighbor *)EVENT_ARG(thread);
+ assert(on);
+
+ if (on->state != OSPF6_NEIGHBOR_LOADING)
+ return;
+
+ if (IS_OSPF6_DEBUG_NEIGHBOR(EVENT))
+ zlog_debug("Neighbor Event %s: *LoadingDone*", on->name);
+
+ assert(on->request_list->count == 0);
+
+ ospf6_neighbor_state_change(OSPF6_NEIGHBOR_FULL, on,
+ OSPF6_NEIGHBOR_EVENT_LOADING_DONE);
+}
+
+void adj_ok(struct event *thread)
+{
+ struct ospf6_neighbor *on;
+
+ on = (struct ospf6_neighbor *)EVENT_ARG(thread);
+ assert(on);
+
+ if (IS_OSPF6_DEBUG_NEIGHBOR(EVENT))
+ zlog_debug("Neighbor Event %s: *AdjOK?*", on->name);
+
+ if (on->state == OSPF6_NEIGHBOR_TWOWAY && need_adjacency(on)) {
+ ospf6_neighbor_state_change(OSPF6_NEIGHBOR_EXSTART, on,
+ OSPF6_NEIGHBOR_EVENT_ADJ_OK);
+ SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT);
+ SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT);
+ SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT);
+
+ EVENT_OFF(on->thread_send_dbdesc);
+ event_add_event(master, ospf6_dbdesc_send, on, 0,
+ &on->thread_send_dbdesc);
+
+ } else if (on->state >= OSPF6_NEIGHBOR_EXSTART && !need_adjacency(on)) {
+ ospf6_neighbor_state_change(OSPF6_NEIGHBOR_TWOWAY, on,
+ OSPF6_NEIGHBOR_EVENT_ADJ_OK);
+ ospf6_neighbor_clear_ls_lists(on);
+ }
+}
+
+void seqnumber_mismatch(struct event *thread)
+{
+ struct ospf6_neighbor *on;
+
+ on = (struct ospf6_neighbor *)EVENT_ARG(thread);
+ assert(on);
+
+ if (on->state < OSPF6_NEIGHBOR_EXCHANGE)
+ return;
+
+ if (IS_OSPF6_DEBUG_NEIGHBOR(EVENT))
+ zlog_debug("Neighbor Event %s: *SeqNumberMismatch*", on->name);
+
+ ospf6_neighbor_state_change(OSPF6_NEIGHBOR_EXSTART, on,
+ OSPF6_NEIGHBOR_EVENT_SEQNUMBER_MISMATCH);
+ SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT);
+ SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT);
+ SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT);
+
+ ospf6_neighbor_clear_ls_lists(on);
+
+ EVENT_OFF(on->thread_send_dbdesc);
+ on->dbdesc_seqnum++; /* Incr seqnum as per RFC2328, sec 10.3 */
+
+ event_add_event(master, ospf6_dbdesc_send, on, 0,
+ &on->thread_send_dbdesc);
+}
+
+void bad_lsreq(struct event *thread)
+{
+ struct ospf6_neighbor *on;
+
+ on = (struct ospf6_neighbor *)EVENT_ARG(thread);
+ assert(on);
+
+ if (on->state < OSPF6_NEIGHBOR_EXCHANGE)
+ return;
+
+ if (IS_OSPF6_DEBUG_NEIGHBOR(EVENT))
+ zlog_debug("Neighbor Event %s: *BadLSReq*", on->name);
+
+ ospf6_neighbor_state_change(OSPF6_NEIGHBOR_EXSTART, on,
+ OSPF6_NEIGHBOR_EVENT_BAD_LSREQ);
+ SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT);
+ SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT);
+ SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT);
+
+ ospf6_neighbor_clear_ls_lists(on);
+
+ EVENT_OFF(on->thread_send_dbdesc);
+ on->dbdesc_seqnum++; /* Incr seqnum as per RFC2328, sec 10.3 */
+
+ event_add_event(master, ospf6_dbdesc_send, on, 0,
+ &on->thread_send_dbdesc);
+}
+
+void oneway_received(struct event *thread)
+{
+ struct ospf6_neighbor *on;
+
+ on = (struct ospf6_neighbor *)EVENT_ARG(thread);
+ assert(on);
+
+ if (on->state < OSPF6_NEIGHBOR_TWOWAY)
+ return;
+
+ if (IS_OSPF6_DEBUG_NEIGHBOR(EVENT))
+ zlog_debug("Neighbor Event %s: *1Way-Received*", on->name);
+
+ ospf6_neighbor_state_change(OSPF6_NEIGHBOR_INIT, on,
+ OSPF6_NEIGHBOR_EVENT_ONEWAY_RCVD);
+ event_add_event(master, neighbor_change, on->ospf6_if, 0, NULL);
+
+ ospf6_neighbor_clear_ls_lists(on);
+
+ EVENT_OFF(on->thread_send_dbdesc);
+ EVENT_OFF(on->thread_send_lsreq);
+ EVENT_OFF(on->thread_send_lsupdate);
+ EVENT_OFF(on->thread_send_lsack);
+ EVENT_OFF(on->thread_exchange_done);
+ EVENT_OFF(on->thread_adj_ok);
+}
+
+void inactivity_timer(struct event *thread)
+{
+ struct ospf6_neighbor *on;
+
+ on = (struct ospf6_neighbor *)EVENT_ARG(thread);
+ assert(on);
+
+ if (IS_OSPF6_DEBUG_NEIGHBOR(EVENT))
+ zlog_debug("Neighbor Event %s: *InactivityTimer*", on->name);
+
+ on->drouter = on->prev_drouter = 0;
+ on->bdrouter = on->prev_bdrouter = 0;
+
+ if (!OSPF6_GR_IS_ACTIVE_HELPER(on)) {
+ on->drouter = on->prev_drouter = 0;
+ on->bdrouter = on->prev_bdrouter = 0;
+
+ ospf6_neighbor_state_change(
+ OSPF6_NEIGHBOR_DOWN, on,
+ OSPF6_NEIGHBOR_EVENT_INACTIVITY_TIMER);
+ event_add_event(master, neighbor_change, on->ospf6_if, 0, NULL);
+
+ listnode_delete(on->ospf6_if->neighbor_list, on);
+ ospf6_neighbor_delete(on);
+
+ } else {
+ if (IS_DEBUG_OSPF6_GR)
+ zlog_debug(
+ "%s, Acting as HELPER for this neighbour, So restart the dead timer.",
+ __PRETTY_FUNCTION__);
+
+ event_add_timer(master, inactivity_timer, on,
+ on->ospf6_if->dead_interval,
+ &on->inactivity_timer);
+ }
+}
+
+
+/* vty functions */
+/* show neighbor structure */
+static void ospf6_neighbor_show(struct vty *vty, struct ospf6_neighbor *on,
+ json_object *json_array, bool use_json)
+{
+ char router_id[16];
+ char duration[64];
+ struct timeval res;
+ char nstate[16];
+ char deadtime[64];
+ long h, m, s;
+ json_object *json_route;
+
+ /* Router-ID (Name) */
+ inet_ntop(AF_INET, &on->router_id, router_id, sizeof(router_id));
+#ifdef HAVE_GETNAMEINFO
+ {
+ }
+#endif /*HAVE_GETNAMEINFO*/
+
+ /* Dead time */
+ h = m = s = 0;
+ if (on->inactivity_timer) {
+ s = monotime_until(&on->inactivity_timer->u.sands, NULL)
+ / 1000000LL;
+ h = s / 3600;
+ s -= h * 3600;
+ m = s / 60;
+ s -= m * 60;
+ }
+ snprintf(deadtime, sizeof(deadtime), "%02ld:%02ld:%02ld", h, m, s);
+
+ /* Neighbor State */
+ if (on->ospf6_if->type == OSPF_IFTYPE_POINTOPOINT)
+ snprintf(nstate, sizeof(nstate), "PointToPoint");
+ else {
+ if (on->router_id == on->drouter)
+ snprintf(nstate, sizeof(nstate), "DR");
+ else if (on->router_id == on->bdrouter)
+ snprintf(nstate, sizeof(nstate), "BDR");
+ else
+ snprintf(nstate, sizeof(nstate), "DROther");
+ }
+
+ /* Duration */
+ monotime_since(&on->last_changed, &res);
+ timerstring(&res, duration, sizeof(duration));
+
+ /*
+ vty_out (vty, "%-15s %3d %11s %6s/%-12s %11s %s[%s]\n",
+ "Neighbor ID", "Pri", "DeadTime", "State", "IfState",
+ "Duration", "I/F", "State");
+ */
+ if (use_json) {
+ json_route = json_object_new_object();
+
+ json_object_string_add(json_route, "neighborId", router_id);
+ json_object_int_add(json_route, "priority", on->priority);
+ json_object_string_add(json_route, "deadTime", deadtime);
+ json_object_string_add(json_route, "state",
+ ospf6_neighbor_state_str[on->state]);
+ json_object_string_add(json_route, "ifState", nstate);
+ json_object_string_add(json_route, "duration", duration);
+ json_object_string_add(json_route, "interfaceName",
+ on->ospf6_if->interface->name);
+ json_object_string_add(
+ json_route, "interfaceState",
+ ospf6_interface_state_str[on->ospf6_if->state]);
+
+ json_object_array_add(json_array, json_route);
+ } else
+ vty_out(vty, "%-15s %3d %11s %8s/%-12s %11s %s[%s]\n",
+ router_id, on->priority, deadtime,
+ ospf6_neighbor_state_str[on->state], nstate, duration,
+ on->ospf6_if->interface->name,
+ ospf6_interface_state_str[on->ospf6_if->state]);
+}
+
+static void ospf6_neighbor_show_drchoice(struct vty *vty,
+ struct ospf6_neighbor *on,
+ json_object *json_array, bool use_json)
+{
+ char router_id[16];
+ char drouter[16], bdrouter[16];
+ char duration[64];
+ struct timeval now, res;
+ json_object *json_route;
+
+ /*
+ vty_out (vty, "%-15s %6s/%-11s %-15s %-15s %s[%s]\n",
+ "RouterID", "State", "Duration", "DR", "BDR", "I/F",
+ "State");
+ */
+
+ inet_ntop(AF_INET, &on->router_id, router_id, sizeof(router_id));
+ inet_ntop(AF_INET, &on->drouter, drouter, sizeof(drouter));
+ inet_ntop(AF_INET, &on->bdrouter, bdrouter, sizeof(bdrouter));
+
+ monotime(&now);
+ timersub(&now, &on->last_changed, &res);
+ timerstring(&res, duration, sizeof(duration));
+
+ if (use_json) {
+ json_route = json_object_new_object();
+ json_object_string_add(json_route, "routerId", router_id);
+ json_object_string_add(json_route, "state",
+ ospf6_neighbor_state_str[on->state]);
+ json_object_string_add(json_route, "duration", duration);
+ json_object_string_add(json_route, "dRouter", drouter);
+ json_object_string_add(json_route, "bdRouter", bdrouter);
+ json_object_string_add(json_route, "interfaceName",
+ on->ospf6_if->interface->name);
+ json_object_string_add(
+ json_route, "interfaceState",
+ ospf6_interface_state_str[on->ospf6_if->state]);
+
+ json_object_array_add(json_array, json_route);
+ } else
+ vty_out(vty, "%-15s %8s/%-11s %-15s %-15s %s[%s]\n", router_id,
+ ospf6_neighbor_state_str[on->state], duration, drouter,
+ bdrouter, on->ospf6_if->interface->name,
+ ospf6_interface_state_str[on->ospf6_if->state]);
+}
+
+static void ospf6_neighbor_show_detail(struct vty *vty,
+ struct ospf6_neighbor *on,
+ json_object *json, bool use_json)
+{
+ char drouter[16], bdrouter[16];
+ char linklocal_addr[64], duration[32];
+ struct timeval now, res;
+ struct ospf6_lsa *lsa, *lsanext;
+ json_object *json_neighbor;
+ json_object *json_array;
+ char db_desc_str[20];
+
+ inet_ntop(AF_INET6, &on->linklocal_addr, linklocal_addr,
+ sizeof(linklocal_addr));
+ inet_ntop(AF_INET, &on->drouter, drouter, sizeof(drouter));
+ inet_ntop(AF_INET, &on->bdrouter, bdrouter, sizeof(bdrouter));
+
+ monotime(&now);
+ timersub(&now, &on->last_changed, &res);
+ timerstring(&res, duration, sizeof(duration));
+
+ if (use_json) {
+ json_neighbor = json_object_new_object();
+ json_object_string_add(json_neighbor, "area",
+ on->ospf6_if->area->name);
+ json_object_string_add(json_neighbor, "interface",
+ on->ospf6_if->interface->name);
+ json_object_int_add(json_neighbor, "interfaceIndex",
+ on->ospf6_if->interface->ifindex);
+ json_object_int_add(json_neighbor, "neighborInterfaceIndex",
+ on->ifindex);
+ json_object_string_add(json_neighbor, "linkLocalAddress",
+ linklocal_addr);
+ json_object_string_add(json_neighbor, "neighborState",
+ ospf6_neighbor_state_str[on->state]);
+ json_object_string_add(json_neighbor, "neighborStateDuration",
+ duration);
+ json_object_string_add(json_neighbor, "neighborDRouter",
+ drouter);
+ json_object_string_add(json_neighbor, "neighborBdRouter",
+ bdrouter);
+ snprintf(db_desc_str, sizeof(db_desc_str), "%s%s%s",
+ (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT)
+ ? "Initial "
+ : ""),
+ (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT)
+ ? "More"
+ : ""),
+ (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT)
+ ? "Master"
+ : "Slave"));
+ json_object_string_add(json_neighbor, "dbDescStatus",
+ db_desc_str);
+
+ json_object_int_add(json_neighbor, "dbDescSeqNumber",
+ (unsigned long)ntohl(on->dbdesc_seqnum));
+
+ json_array = json_object_new_array();
+ json_object_int_add(json_neighbor, "summaryListCount",
+ on->summary_list->count);
+ for (ALL_LSDB(on->summary_list, lsa, lsanext))
+ json_object_array_add(
+ json_array, json_object_new_string(lsa->name));
+ json_object_object_add(json_neighbor, "summaryListLsa",
+ json_array);
+
+ json_array = json_object_new_array();
+ json_object_int_add(json_neighbor, "requestListCount",
+ on->request_list->count);
+ for (ALL_LSDB(on->request_list, lsa, lsanext))
+ json_object_array_add(
+ json_array, json_object_new_string(lsa->name));
+ json_object_object_add(json_neighbor, "requestListLsa",
+ json_array);
+
+ json_array = json_object_new_array();
+ json_object_int_add(json_neighbor, "reTransListCount",
+ on->retrans_list->count);
+ for (ALL_LSDB(on->retrans_list, lsa, lsanext))
+ json_object_array_add(
+ json_array, json_object_new_string(lsa->name));
+ json_object_object_add(json_neighbor, "reTransListLsa",
+ json_array);
+
+
+ timerclear(&res);
+ if (event_is_scheduled(on->thread_send_dbdesc))
+ timersub(&on->thread_send_dbdesc->u.sands, &now, &res);
+ timerstring(&res, duration, sizeof(duration));
+ json_object_int_add(json_neighbor, "pendingLsaDbDescCount",
+ on->dbdesc_list->count);
+ json_object_string_add(json_neighbor, "pendingLsaDbDescTime",
+ duration);
+ json_object_string_add(
+ json_neighbor, "dbDescSendThread",
+ (event_is_scheduled(on->thread_send_dbdesc) ? "on"
+ : "off"));
+ json_array = json_object_new_array();
+ for (ALL_LSDB(on->dbdesc_list, lsa, lsanext))
+ json_object_array_add(
+ json_array, json_object_new_string(lsa->name));
+ json_object_object_add(json_neighbor, "pendingLsaDbDesc",
+ json_array);
+
+ timerclear(&res);
+ if (event_is_scheduled(on->thread_send_lsreq))
+ timersub(&on->thread_send_lsreq->u.sands, &now, &res);
+ timerstring(&res, duration, sizeof(duration));
+ json_object_int_add(json_neighbor, "pendingLsaLsReqCount",
+ on->request_list->count);
+ json_object_string_add(json_neighbor, "pendingLsaLsReqTime",
+ duration);
+ json_object_string_add(
+ json_neighbor, "lsReqSendThread",
+ (event_is_scheduled(on->thread_send_lsreq) ? "on"
+ : "off"));
+ json_array = json_object_new_array();
+ for (ALL_LSDB(on->request_list, lsa, lsanext))
+ json_object_array_add(
+ json_array, json_object_new_string(lsa->name));
+ json_object_object_add(json_neighbor, "pendingLsaLsReq",
+ json_array);
+
+
+ timerclear(&res);
+ if (event_is_scheduled(on->thread_send_lsupdate))
+ timersub(&on->thread_send_lsupdate->u.sands, &now,
+ &res);
+ timerstring(&res, duration, sizeof(duration));
+ json_object_int_add(json_neighbor, "pendingLsaLsUpdateCount",
+ on->lsupdate_list->count);
+ json_object_string_add(json_neighbor, "pendingLsaLsUpdateTime",
+ duration);
+ json_object_string_add(
+ json_neighbor, "lsUpdateSendThread",
+ (event_is_scheduled(on->thread_send_lsupdate) ? "on"
+ : "off"));
+ json_array = json_object_new_array();
+ for (ALL_LSDB(on->lsupdate_list, lsa, lsanext))
+ json_object_array_add(
+ json_array, json_object_new_string(lsa->name));
+ json_object_object_add(json_neighbor, "pendingLsaLsUpdate",
+ json_array);
+
+ timerclear(&res);
+ if (event_is_scheduled(on->thread_send_lsack))
+ timersub(&on->thread_send_lsack->u.sands, &now, &res);
+ timerstring(&res, duration, sizeof(duration));
+ json_object_int_add(json_neighbor, "pendingLsaLsAckCount",
+ on->lsack_list->count);
+ json_object_string_add(json_neighbor, "pendingLsaLsAckTime",
+ duration);
+ json_object_string_add(
+ json_neighbor, "lsAckSendThread",
+ (event_is_scheduled(on->thread_send_lsack) ? "on"
+ : "off"));
+ json_array = json_object_new_array();
+ for (ALL_LSDB(on->lsack_list, lsa, lsanext))
+ json_object_array_add(
+ json_array, json_object_new_string(lsa->name));
+ json_object_object_add(json_neighbor, "pendingLsaLsAck",
+ json_array);
+
+ bfd_sess_show(vty, json_neighbor, on->bfd_session);
+
+ if (on->auth_present == true) {
+ json_object_string_add(json_neighbor, "authStatus",
+ "enabled");
+ json_object_int_add(
+ json_neighbor, "recvdHelloHigherSeqNo",
+ on->seqnum_h[OSPF6_MESSAGE_TYPE_HELLO]);
+ json_object_int_add(
+ json_neighbor, "recvdHelloLowerSeqNo",
+ on->seqnum_l[OSPF6_MESSAGE_TYPE_HELLO]);
+ json_object_int_add(
+ json_neighbor, "recvdDBDescHigherSeqNo",
+ on->seqnum_h[OSPF6_MESSAGE_TYPE_DBDESC]);
+ json_object_int_add(
+ json_neighbor, "recvdDBDescLowerSeqNo",
+ on->seqnum_l[OSPF6_MESSAGE_TYPE_DBDESC]);
+ json_object_int_add(
+ json_neighbor, "recvdLSReqHigherSeqNo",
+ on->seqnum_h[OSPF6_MESSAGE_TYPE_LSREQ]);
+ json_object_int_add(
+ json_neighbor, "recvdLSReqLowerSeqNo",
+ on->seqnum_l[OSPF6_MESSAGE_TYPE_LSREQ]);
+ json_object_int_add(
+ json_neighbor, "recvdLSUpdHigherSeqNo",
+ on->seqnum_h[OSPF6_MESSAGE_TYPE_LSUPDATE]);
+ json_object_int_add(
+ json_neighbor, "recvdLSUpdLowerSeqNo",
+ on->seqnum_l[OSPF6_MESSAGE_TYPE_LSUPDATE]);
+ json_object_int_add(
+ json_neighbor, "recvdLSAckHigherSeqNo",
+ on->seqnum_h[OSPF6_MESSAGE_TYPE_LSACK]);
+ json_object_int_add(
+ json_neighbor, "recvdLSAckLowerSeqNo",
+ on->seqnum_l[OSPF6_MESSAGE_TYPE_LSACK]);
+ } else
+ json_object_string_add(json_neighbor, "authStatus",
+ "disabled");
+
+ json_object_object_add(json, on->name, json_neighbor);
+
+ } else {
+ vty_out(vty, " Neighbor %s\n", on->name);
+ vty_out(vty, " Area %s via interface %s (ifindex %d)\n",
+ on->ospf6_if->area->name, on->ospf6_if->interface->name,
+ on->ospf6_if->interface->ifindex);
+ vty_out(vty, " His IfIndex: %d Link-local address: %s\n",
+ on->ifindex, linklocal_addr);
+ vty_out(vty, " State %s for a duration of %s\n",
+ ospf6_neighbor_state_str[on->state], duration);
+ vty_out(vty, " His choice of DR/BDR %s/%s, Priority %d\n",
+ drouter, bdrouter, on->priority);
+ vty_out(vty, " DbDesc status: %s%s%s SeqNum: %#lx\n",
+ (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT)
+ ? "Initial "
+ : ""),
+ (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT)
+ ? "More "
+ : ""),
+ (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT)
+ ? "Master"
+ : "Slave"),
+ (unsigned long)ntohl(on->dbdesc_seqnum));
+
+ vty_out(vty, " Summary-List: %d LSAs\n",
+ on->summary_list->count);
+ for (ALL_LSDB(on->summary_list, lsa, lsanext))
+ vty_out(vty, " %s\n", lsa->name);
+
+ vty_out(vty, " Request-List: %d LSAs\n",
+ on->request_list->count);
+ for (ALL_LSDB(on->request_list, lsa, lsanext))
+ vty_out(vty, " %s\n", lsa->name);
+
+ vty_out(vty, " Retrans-List: %d LSAs\n",
+ on->retrans_list->count);
+ for (ALL_LSDB(on->retrans_list, lsa, lsanext))
+ vty_out(vty, " %s\n", lsa->name);
+
+ timerclear(&res);
+ if (event_is_scheduled(on->thread_send_dbdesc))
+ timersub(&on->thread_send_dbdesc->u.sands, &now, &res);
+ timerstring(&res, duration, sizeof(duration));
+ vty_out(vty,
+ " %d Pending LSAs for DbDesc in Time %s [thread %s]\n",
+ on->dbdesc_list->count, duration,
+ (event_is_scheduled(on->thread_send_dbdesc) ? "on"
+ : "off"));
+ for (ALL_LSDB(on->dbdesc_list, lsa, lsanext))
+ vty_out(vty, " %s\n", lsa->name);
+
+ timerclear(&res);
+ if (event_is_scheduled(on->thread_send_lsreq))
+ timersub(&on->thread_send_lsreq->u.sands, &now, &res);
+ timerstring(&res, duration, sizeof(duration));
+ vty_out(vty,
+ " %d Pending LSAs for LSReq in Time %s [thread %s]\n",
+ on->request_list->count, duration,
+ (event_is_scheduled(on->thread_send_lsreq) ? "on"
+ : "off"));
+ for (ALL_LSDB(on->request_list, lsa, lsanext))
+ vty_out(vty, " %s\n", lsa->name);
+
+ timerclear(&res);
+ if (event_is_scheduled(on->thread_send_lsupdate))
+ timersub(&on->thread_send_lsupdate->u.sands, &now,
+ &res);
+ timerstring(&res, duration, sizeof(duration));
+ vty_out(vty,
+ " %d Pending LSAs for LSUpdate in Time %s [thread %s]\n",
+ on->lsupdate_list->count, duration,
+ (event_is_scheduled(on->thread_send_lsupdate) ? "on"
+ : "off"));
+ for (ALL_LSDB(on->lsupdate_list, lsa, lsanext))
+ vty_out(vty, " %s\n", lsa->name);
+
+ timerclear(&res);
+ if (event_is_scheduled(on->thread_send_lsack))
+ timersub(&on->thread_send_lsack->u.sands, &now, &res);
+ timerstring(&res, duration, sizeof(duration));
+ vty_out(vty,
+ " %d Pending LSAs for LSAck in Time %s [thread %s]\n",
+ on->lsack_list->count, duration,
+ (event_is_scheduled(on->thread_send_lsack) ? "on"
+ : "off"));
+ for (ALL_LSDB(on->lsack_list, lsa, lsanext))
+ vty_out(vty, " %s\n", lsa->name);
+
+ bfd_sess_show(vty, NULL, on->bfd_session);
+
+ if (on->auth_present == true) {
+ vty_out(vty, " Authentication header present\n");
+ vty_out(vty,
+ "\t\t\t hello DBDesc LSReq LSUpd LSAck\n");
+ vty_out(vty,
+ " Higher sequence no 0x%-10X 0x%-10X 0x%-10X 0x%-10X 0x%-10X\n",
+ on->seqnum_h[OSPF6_MESSAGE_TYPE_HELLO],
+ on->seqnum_h[OSPF6_MESSAGE_TYPE_DBDESC],
+ on->seqnum_h[OSPF6_MESSAGE_TYPE_LSREQ],
+ on->seqnum_h[OSPF6_MESSAGE_TYPE_LSUPDATE],
+ on->seqnum_h[OSPF6_MESSAGE_TYPE_LSACK]);
+ vty_out(vty,
+ " Lower sequence no 0x%-10X 0x%-10X 0x%-10X 0x%-10X 0x%-10X\n",
+ on->seqnum_l[OSPF6_MESSAGE_TYPE_HELLO],
+ on->seqnum_l[OSPF6_MESSAGE_TYPE_DBDESC],
+ on->seqnum_l[OSPF6_MESSAGE_TYPE_LSREQ],
+ on->seqnum_l[OSPF6_MESSAGE_TYPE_LSUPDATE],
+ on->seqnum_l[OSPF6_MESSAGE_TYPE_LSACK]);
+ } else
+ vty_out(vty, " Authentication header not present\n");
+ }
+}
+
+static void ospf6_neighbor_show_detail_common(struct vty *vty,
+ struct ospf6 *ospf6, bool uj,
+ bool detail, bool drchoice)
+{
+ struct ospf6_neighbor *on;
+ struct ospf6_interface *oi;
+ struct ospf6_area *oa;
+ struct listnode *i, *j, *k;
+ json_object *json = NULL;
+ json_object *json_array = NULL;
+ void (*showfunc)(struct vty *, struct ospf6_neighbor *,
+ json_object *json, bool use_json);
+
+ if (detail)
+ showfunc = ospf6_neighbor_show_detail;
+ else if (drchoice)
+ showfunc = ospf6_neighbor_show_drchoice;
+ else
+ showfunc = ospf6_neighbor_show;
+
+ if (uj) {
+ json = json_object_new_object();
+ json_array = json_object_new_array();
+ } else {
+ if (showfunc == ospf6_neighbor_show)
+ vty_out(vty, "%-15s %3s %11s %8s/%-12s %11s %s[%s]\n",
+ "Neighbor ID", "Pri", "DeadTime", "State",
+ "IfState", "Duration", "I/F", "State");
+ else if (showfunc == ospf6_neighbor_show_drchoice)
+ vty_out(vty, "%-15s %8s/%-11s %-15s %-15s %s[%s]\n",
+ "RouterID", "State", "Duration", "DR", "BDR",
+ "I/F", "State");
+ }
+
+ for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa))
+ for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi))
+ for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k, on)) {
+ if (showfunc == ospf6_neighbor_show_detail)
+ (*showfunc)(vty, on, json, uj);
+ else
+ (*showfunc)(vty, on, json_array, uj);
+ }
+
+ if (uj) {
+ if (showfunc != ospf6_neighbor_show_detail)
+ json_object_object_add(json, "neighbors", json_array);
+ else
+ json_object_free(json_array);
+ vty_json(vty, json);
+ }
+}
+
+DEFUN(show_ipv6_ospf6_neighbor, show_ipv6_ospf6_neighbor_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] neighbor [<detail|drchoice>] [json]",
+ SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "Neighbor list\n"
+ "Display details\n"
+ "Display DR choices\n" JSON_STR)
+{
+ struct ospf6 *ospf6;
+ struct listnode *node;
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+ int idx_type = 4;
+ bool uj = use_json(argc, argv);
+ bool detail = false;
+ bool drchoice = false;
+
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+
+ if (argv_find(argv, argc, "detail", &idx_type))
+ detail = true;
+ else if (argv_find(argv, argc, "drchoice", &idx_type))
+ drchoice = true;
+
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ ospf6_neighbor_show_detail_common(vty, ospf6, uj,
+ detail, drchoice);
+ if (!all_vrf)
+ break;
+ }
+ }
+
+ OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6);
+
+ return CMD_SUCCESS;
+}
+
+static int ospf6_neighbor_show_common(struct vty *vty, int argc,
+ struct cmd_token **argv,
+ struct ospf6 *ospf6, int idx_ipv4,
+ bool uj)
+{
+ struct ospf6_neighbor *on;
+ struct ospf6_interface *oi;
+ struct ospf6_area *oa;
+ struct listnode *i, *j, *k;
+ void (*showfunc)(struct vty *, struct ospf6_neighbor *,
+ json_object *json, bool use_json);
+ uint32_t router_id;
+ json_object *json = NULL;
+
+ showfunc = ospf6_neighbor_show_detail;
+ if (uj)
+ json = json_object_new_object();
+
+ if ((inet_pton(AF_INET, argv[idx_ipv4]->arg, &router_id)) != 1) {
+ vty_out(vty, "Router-ID is not parsable: %s\n",
+ argv[idx_ipv4]->arg);
+ return CMD_SUCCESS;
+ }
+
+ for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, i, oa))
+ for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi))
+ for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k, on)) {
+ if (router_id == on->router_id)
+ (*showfunc)(vty, on, json, uj);
+ }
+
+ if (uj)
+ vty_json(vty, json);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(show_ipv6_ospf6_neighbor_one, show_ipv6_ospf6_neighbor_one_cmd,
+ "show ipv6 ospf6 [vrf <NAME|all>] neighbor A.B.C.D [json]",
+ SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "Neighbor list\n"
+ "Specify Router-ID as IPv4 address notation\n" JSON_STR)
+{
+ int idx_ipv4 = 4;
+ struct ospf6 *ospf6;
+ struct listnode *node;
+ const char *vrf_name = NULL;
+ bool all_vrf = false;
+ int idx_vrf = 0;
+ bool uj = use_json(argc, argv);
+
+ OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+ if (idx_vrf > 0)
+ idx_ipv4 += 2;
+
+ for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
+ if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
+ ospf6_neighbor_show_common(vty, argc, argv, ospf6,
+ idx_ipv4, uj);
+
+ if (!all_vrf)
+ break;
+ }
+ }
+
+ OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6);
+
+ return CMD_SUCCESS;
+}
+
+void ospf6_neighbor_init(void)
+{
+ install_element(VIEW_NODE, &show_ipv6_ospf6_neighbor_cmd);
+ install_element(VIEW_NODE, &show_ipv6_ospf6_neighbor_one_cmd);
+}
+
+DEFUN (debug_ospf6_neighbor,
+ debug_ospf6_neighbor_cmd,
+ "debug ospf6 neighbor [<state|event>]",
+ DEBUG_STR
+ OSPF6_STR
+ "Debug OSPFv3 Neighbor\n"
+ "Debug OSPFv3 Neighbor State Change\n"
+ "Debug OSPFv3 Neighbor Event\n")
+{
+ int idx_type = 3;
+ unsigned char level = 0;
+
+ if (argc == 4) {
+ if (!strncmp(argv[idx_type]->arg, "s", 1))
+ level = OSPF6_DEBUG_NEIGHBOR_STATE;
+ else if (!strncmp(argv[idx_type]->arg, "e", 1))
+ level = OSPF6_DEBUG_NEIGHBOR_EVENT;
+ } else
+ level = OSPF6_DEBUG_NEIGHBOR_STATE | OSPF6_DEBUG_NEIGHBOR_EVENT;
+
+ OSPF6_DEBUG_NEIGHBOR_ON(level);
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (no_debug_ospf6_neighbor,
+ no_debug_ospf6_neighbor_cmd,
+ "no debug ospf6 neighbor [<state|event>]",
+ NO_STR
+ DEBUG_STR
+ OSPF6_STR
+ "Debug OSPFv3 Neighbor\n"
+ "Debug OSPFv3 Neighbor State Change\n"
+ "Debug OSPFv3 Neighbor Event\n")
+{
+ int idx_type = 4;
+ unsigned char level = 0;
+
+ if (argc == 5) {
+ if (!strncmp(argv[idx_type]->arg, "s", 1))
+ level = OSPF6_DEBUG_NEIGHBOR_STATE;
+ if (!strncmp(argv[idx_type]->arg, "e", 1))
+ level = OSPF6_DEBUG_NEIGHBOR_EVENT;
+ } else
+ level = OSPF6_DEBUG_NEIGHBOR_STATE | OSPF6_DEBUG_NEIGHBOR_EVENT;
+
+ OSPF6_DEBUG_NEIGHBOR_OFF(level);
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (no_debug_ospf6,
+ no_debug_ospf6_cmd,
+ "no debug ospf6",
+ NO_STR
+ DEBUG_STR
+ OSPF6_STR)
+{
+ unsigned int i;
+
+ OSPF6_DEBUG_ABR_OFF();
+ OSPF6_DEBUG_ASBR_OFF();
+ OSPF6_DEBUG_BROUTER_OFF();
+ OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_OFF();
+ OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_OFF();
+ OSPF6_DEBUG_FLOODING_OFF();
+ OSPF6_DEBUG_INTERFACE_OFF();
+
+ ospf6_lsa_debug_set_all(false);
+
+ for (i = 0; i < 6; i++)
+ OSPF6_DEBUG_MESSAGE_OFF(i,
+ OSPF6_DEBUG_NEIGHBOR_STATE
+ | OSPF6_DEBUG_NEIGHBOR_EVENT);
+
+ OSPF6_DEBUG_NEIGHBOR_OFF(OSPF6_DEBUG_NEIGHBOR_STATE
+ | OSPF6_DEBUG_NEIGHBOR_EVENT);
+ OSPF6_DEBUG_ROUTE_OFF(OSPF6_DEBUG_ROUTE_TABLE);
+ OSPF6_DEBUG_ROUTE_OFF(OSPF6_DEBUG_ROUTE_INTRA);
+ OSPF6_DEBUG_ROUTE_OFF(OSPF6_DEBUG_ROUTE_INTER);
+ OSPF6_DEBUG_ROUTE_OFF(OSPF6_DEBUG_ROUTE_MEMORY);
+ OSPF6_DEBUG_SPF_OFF(OSPF6_DEBUG_SPF_PROCESS);
+ OSPF6_DEBUG_SPF_OFF(OSPF6_DEBUG_SPF_TIME);
+ OSPF6_DEBUG_SPF_OFF(OSPF6_DEBUG_SPF_DATABASE);
+ OSPF6_DEBUG_ZEBRA_OFF(OSPF6_DEBUG_ZEBRA_SEND | OSPF6_DEBUG_ZEBRA_RECV);
+
+ return CMD_SUCCESS;
+}
+
+int config_write_ospf6_debug_neighbor(struct vty *vty)
+{
+ if (IS_OSPF6_DEBUG_NEIGHBOR(STATE) && IS_OSPF6_DEBUG_NEIGHBOR(EVENT))
+ vty_out(vty, "debug ospf6 neighbor\n");
+ else if (IS_OSPF6_DEBUG_NEIGHBOR(STATE))
+ vty_out(vty, "debug ospf6 neighbor state\n");
+ else if (IS_OSPF6_DEBUG_NEIGHBOR(EVENT))
+ vty_out(vty, "debug ospf6 neighbor event\n");
+ return 0;
+}
+
+void install_element_ospf6_debug_neighbor(void)
+{
+ install_element(ENABLE_NODE, &debug_ospf6_neighbor_cmd);
+ install_element(ENABLE_NODE, &no_debug_ospf6_neighbor_cmd);
+ install_element(ENABLE_NODE, &no_debug_ospf6_cmd);
+ install_element(CONFIG_NODE, &debug_ospf6_neighbor_cmd);
+ install_element(CONFIG_NODE, &no_debug_ospf6_neighbor_cmd);
+ install_element(CONFIG_NODE, &no_debug_ospf6_cmd);
+}