mirror_frr/ospf6d/ospf6_neighbor.c
Donald Sharp 7f342629a9 This patch changes ospfd from only listening mode for BFD status updates to interactive mode of dynamically registering/deregistering neighbors discovered on BFD enabled interfaces with PTM/BFD through zebra. Neighbor is registered with BFD when 2-way adjacency is established and deregistered when adjacency goes down if the BFD is enabled on the interface through which the neighbor was discovered.
OSPF BFD command enhancement to configure BFD parameters (detect multiplier, min rx and min tx).
interface <if-name>
  ip ospf bfd <detect mult> <min rx> <min tx>

This patch also adds BFD support for IPv6 OSPF. ospf6d  will dynamically register/deregister IPv6 neighbors with BFD for monitoring the connectivity of the neighbor. Neighbor is registered with BFD when 2-way adjacency is established and deregistered when adjacency goes down if the BFD is enabled on the interface through which the neighbor was discovered.

OSPF6 BFD command added to configure BFD and parameters (detect multiplier, min rx and min tx).
interface <if-name>
  ipv6 ospf6 bfd <detect mult> <min rx> <min tx>

Signed-off-by: Radhika Mahankali <radhika@cumulusnetworks.com>
Reviewed-by:   Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by:   Kanna Rajagopal <kanna@cumulusnetworks.com>
2015-07-22 12:35:37 -07:00

1014 lines
29 KiB
C

/*
* Copyright (C) 2003 Yasuhiro Ohara
*
* This file is part of GNU Zebra.
*
* GNU Zebra 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, or (at your option) any
* later version.
*
* GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <zebra.h>
#include "log.h"
#include "memory.h"
#include "thread.h"
#include "linklist.h"
#include "vty.h"
#include "command.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"
unsigned char conf_debug_ospf6_neighbor = 0;
const char *ospf6_neighbor_state_str[] =
{ "None", "Down", "Attempt", "Init", "Twoway", "ExStart", "ExChange",
"Loading", "Full", NULL };
int
ospf6_neighbor_cmp (void *va, void *vb)
{
struct ospf6_neighbor *ona = (struct ospf6_neighbor *) va;
struct ospf6_neighbor *onb = (struct ospf6_neighbor *) vb;
return (ntohl (ona->router_id) < ntohl (onb->router_id) ? -1 : 1);
}
struct ospf6_neighbor *
ospf6_neighbor_lookup (u_int32_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;
}
/* create ospf6_neighbor */
struct ospf6_neighbor *
ospf6_neighbor_create (u_int32_t router_id, struct ospf6_interface *oi)
{
struct ospf6_neighbor *on;
char buf[16];
on = (struct ospf6_neighbor *)
XMALLOC (MTYPE_OSPF6_NEIGHBOR, sizeof (struct ospf6_neighbor));
if (on == NULL)
{
zlog_warn ("neighbor: malloc failed");
return NULL;
}
memset (on, 0, 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;
quagga_gettime (QUAGGA_CLK_MONOTONIC, &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);
listnode_add_sort (oi->neighbor_list, on);
return on;
}
void
ospf6_neighbor_delete (struct ospf6_neighbor *on)
{
struct ospf6_lsa *lsa;
ospf6_lsdb_remove_all (on->summary_list);
ospf6_lsdb_remove_all (on->request_list);
for (lsa = ospf6_lsdb_head (on->retrans_list); lsa;
lsa = ospf6_lsdb_next (lsa))
{
ospf6_decrement_retrans_count (lsa);
ospf6_lsdb_remove (lsa, on->retrans_list);
}
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);
THREAD_OFF (on->inactivity_timer);
THREAD_OFF (on->thread_send_dbdesc);
THREAD_OFF (on->thread_send_lsreq);
THREAD_OFF (on->thread_send_lsupdate);
THREAD_OFF (on->thread_send_lsack);
XFREE (MTYPE_OSPF6_NEIGHBOR, on);
}
static void
ospf6_neighbor_state_change (u_char next_state, struct ospf6_neighbor *on, int event)
{
u_char prev_state;
prev_state = on->state;
on->state = next_state;
if (prev_state == next_state)
return;
on->state_change++;
quagga_gettime (QUAGGA_CLK_MONOTONIC, &on->last_changed);
/* log */
if (IS_OSPF6_DEBUG_NEIGHBOR (STATE))
{
zlog_debug ("Neighbor state change %s: [%s]->[%s] (%s)", on->name,
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 %s: %s -> %s (%s)", 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)
{
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);
}
OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB (on->ospf6_if->area);
}
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);
#ifdef HAVE_SNMP
/* Terminal state or regression */
if ((next_state == OSPF6_NEIGHBOR_FULL) ||
(next_state == OSPF6_NEIGHBOR_TWOWAY) ||
(next_state < prev_state))
ospf6TrapNbrStateChange (on);
#endif
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;
}
int
hello_received (struct thread *thread)
{
struct ospf6_neighbor *on;
on = (struct ospf6_neighbor *) THREAD_ARG (thread);
assert (on);
if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT))
zlog_debug ("Neighbor Event %s: *HelloReceived*", on->name);
/* reset Inactivity Timer */
THREAD_OFF (on->inactivity_timer);
on->inactivity_timer = thread_add_timer (master, inactivity_timer, on,
on->ospf6_if->dead_interval);
if (on->state <= OSPF6_NEIGHBOR_DOWN)
ospf6_neighbor_state_change (OSPF6_NEIGHBOR_INIT, on,
OSPF6_NEIGHBOR_EVENT_HELLO_RCVD);
return 0;
}
int
twoway_received (struct thread *thread)
{
struct ospf6_neighbor *on;
on = (struct ospf6_neighbor *) THREAD_ARG (thread);
assert (on);
if (on->state > OSPF6_NEIGHBOR_INIT)
return 0;
if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT))
zlog_debug ("Neighbor Event %s: *2Way-Received*", on->name);
thread_add_event (master, neighbor_change, on->ospf6_if, 0);
if (! need_adjacency (on))
{
ospf6_neighbor_state_change (OSPF6_NEIGHBOR_TWOWAY, on,
OSPF6_NEIGHBOR_EVENT_TWOWAY_RCVD);
return 0;
}
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);
THREAD_OFF (on->thread_send_dbdesc);
on->thread_send_dbdesc =
thread_add_event (master, ospf6_dbdesc_send, on, 0);
return 0;
}
int
negotiation_done (struct thread *thread)
{
struct ospf6_neighbor *on;
struct ospf6_lsa *lsa;
on = (struct ospf6_neighbor *) THREAD_ARG (thread);
assert (on);
if (on->state != OSPF6_NEIGHBOR_EXSTART)
return 0;
if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT))
zlog_debug ("Neighbor Event %s: *NegotiationDone*", on->name);
/* clear ls-list */
ospf6_lsdb_remove_all (on->summary_list);
ospf6_lsdb_remove_all (on->request_list);
for (lsa = ospf6_lsdb_head (on->retrans_list); lsa;
lsa = ospf6_lsdb_next (lsa))
{
ospf6_decrement_retrans_count (lsa);
ospf6_lsdb_remove (lsa, on->retrans_list);
}
/* Interface scoped LSAs */
for (lsa = ospf6_lsdb_head (on->ospf6_if->lsdb); lsa;
lsa = ospf6_lsdb_next (lsa))
{
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 (lsa = ospf6_lsdb_head (on->ospf6_if->area->lsdb); lsa;
lsa = ospf6_lsdb_next (lsa))
{
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 (lsa = ospf6_lsdb_head (on->ospf6_if->area->ospf6->lsdb); lsa;
lsa = ospf6_lsdb_next (lsa))
{
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);
return 0;
}
int
exchange_done (struct thread *thread)
{
struct ospf6_neighbor *on;
on = (struct ospf6_neighbor *) THREAD_ARG (thread);
assert (on);
if (on->state != OSPF6_NEIGHBOR_EXCHANGE)
return 0;
if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT))
zlog_debug ("Neighbor Event %s: *ExchangeDone*", on->name);
THREAD_OFF (on->thread_send_dbdesc);
ospf6_lsdb_remove_all (on->dbdesc_list);
/* XXX
thread_add_timer (master, ospf6_neighbor_last_dbdesc_release, on,
on->ospf6_if->dead_interval);
*/
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);
if (on->thread_send_lsreq == NULL)
on->thread_send_lsreq =
thread_add_event (master, ospf6_lsreq_send, on, 0);
}
return 0;
}
/* 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)
thread_add_event (master, loading_done, on, 0);
else if (on->last_ls_req == NULL)
{
if (on->thread_send_lsreq != NULL)
THREAD_OFF (on->thread_send_lsreq);
on->thread_send_lsreq =
thread_add_event (master, ospf6_lsreq_send, on, 0);
}
}
}
int
loading_done (struct thread *thread)
{
struct ospf6_neighbor *on;
on = (struct ospf6_neighbor *) THREAD_ARG (thread);
assert (on);
if (on->state != OSPF6_NEIGHBOR_LOADING)
return 0;
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);
return 0;
}
int
adj_ok (struct thread *thread)
{
struct ospf6_neighbor *on;
struct ospf6_lsa *lsa;
on = (struct ospf6_neighbor *) THREAD_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);
THREAD_OFF (on->thread_send_dbdesc);
on->thread_send_dbdesc =
thread_add_event (master, ospf6_dbdesc_send, on, 0);
}
else if (on->state >= OSPF6_NEIGHBOR_EXSTART &&
! need_adjacency (on))
{
ospf6_neighbor_state_change (OSPF6_NEIGHBOR_TWOWAY, on,
OSPF6_NEIGHBOR_EVENT_ADJ_OK);
ospf6_lsdb_remove_all (on->summary_list);
ospf6_lsdb_remove_all (on->request_list);
for (lsa = ospf6_lsdb_head (on->retrans_list); lsa;
lsa = ospf6_lsdb_next (lsa))
{
ospf6_decrement_retrans_count (lsa);
ospf6_lsdb_remove (lsa, on->retrans_list);
}
}
return 0;
}
int
seqnumber_mismatch (struct thread *thread)
{
struct ospf6_neighbor *on;
struct ospf6_lsa *lsa;
on = (struct ospf6_neighbor *) THREAD_ARG (thread);
assert (on);
if (on->state < OSPF6_NEIGHBOR_EXCHANGE)
return 0;
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_lsdb_remove_all (on->summary_list);
ospf6_lsdb_remove_all (on->request_list);
for (lsa = ospf6_lsdb_head (on->retrans_list); lsa;
lsa = ospf6_lsdb_next (lsa))
{
ospf6_decrement_retrans_count (lsa);
ospf6_lsdb_remove (lsa, on->retrans_list);
}
THREAD_OFF (on->thread_send_dbdesc);
on->dbdesc_seqnum++; /* Incr seqnum as per RFC2328, sec 10.3 */
on->thread_send_dbdesc =
thread_add_event (master, ospf6_dbdesc_send, on, 0);
return 0;
}
int
bad_lsreq (struct thread *thread)
{
struct ospf6_neighbor *on;
struct ospf6_lsa *lsa;
on = (struct ospf6_neighbor *) THREAD_ARG (thread);
assert (on);
if (on->state < OSPF6_NEIGHBOR_EXCHANGE)
return 0;
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_lsdb_remove_all (on->summary_list);
ospf6_lsdb_remove_all (on->request_list);
for (lsa = ospf6_lsdb_head (on->retrans_list); lsa;
lsa = ospf6_lsdb_next (lsa))
{
ospf6_decrement_retrans_count (lsa);
ospf6_lsdb_remove (lsa, on->retrans_list);
}
THREAD_OFF (on->thread_send_dbdesc);
on->dbdesc_seqnum++; /* Incr seqnum as per RFC2328, sec 10.3 */
on->thread_send_dbdesc =
thread_add_event (master, ospf6_dbdesc_send, on, 0);
return 0;
}
int
oneway_received (struct thread *thread)
{
struct ospf6_neighbor *on;
struct ospf6_lsa *lsa;
on = (struct ospf6_neighbor *) THREAD_ARG (thread);
assert (on);
if (on->state < OSPF6_NEIGHBOR_TWOWAY)
return 0;
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);
thread_add_event (master, neighbor_change, on->ospf6_if, 0);
ospf6_lsdb_remove_all (on->summary_list);
ospf6_lsdb_remove_all (on->request_list);
for (lsa = ospf6_lsdb_head (on->retrans_list); lsa;
lsa = ospf6_lsdb_next (lsa))
{
ospf6_decrement_retrans_count (lsa);
ospf6_lsdb_remove (lsa, on->retrans_list);
}
THREAD_OFF (on->thread_send_dbdesc);
THREAD_OFF (on->thread_send_lsreq);
THREAD_OFF (on->thread_send_lsupdate);
THREAD_OFF (on->thread_send_lsack);
return 0;
}
int
inactivity_timer (struct thread *thread)
{
struct ospf6_neighbor *on;
on = (struct ospf6_neighbor *) THREAD_ARG (thread);
assert (on);
if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT))
zlog_debug ("Neighbor Event %s: *InactivityTimer*", on->name);
on->inactivity_timer = NULL;
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);
thread_add_event (master, neighbor_change, on->ospf6_if, 0);
listnode_delete (on->ospf6_if->neighbor_list, on);
ospf6_neighbor_delete (on);
return 0;
}
/* vty functions */
/* show neighbor structure */
static void
ospf6_neighbor_show (struct vty *vty, struct ospf6_neighbor *on)
{
char router_id[16];
char duration[16];
struct timeval now, res;
char nstate[16];
char deadtime[16];
long h, m, s;
/* Router-ID (Name) */
inet_ntop (AF_INET, &on->router_id, router_id, sizeof (router_id));
#ifdef HAVE_GETNAMEINFO
{
}
#endif /*HAVE_GETNAMEINFO*/
quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
/* Dead time */
h = m = s = 0;
if (on->inactivity_timer)
{
s = on->inactivity_timer->u.sands.tv_sec - recent_relative_time().tv_sec;
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 (if_is_pointopoint (on->ospf6_if->interface))
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 */
timersub (&now, &on->last_changed, &res);
timerstring (&res, duration, sizeof (duration));
/*
vty_out (vty, "%-15s %3d %11s %6s/%-12s %11s %s[%s]%s",
"Neighbor ID", "Pri", "DeadTime", "State", "", "Duration",
"I/F", "State", VNL);
*/
vty_out (vty, "%-15s %3d %11s %6s/%-12s %11s %s[%s]%s",
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], VNL);
}
static void
ospf6_neighbor_show_drchoice (struct vty *vty, struct ospf6_neighbor *on)
{
char router_id[16];
char drouter[16], bdrouter[16];
char duration[16];
struct timeval now, res;
/*
vty_out (vty, "%-15s %6s/%-11s %-15s %-15s %s[%s]%s",
"RouterID", "State", "Duration", "DR", "BDR", "I/F",
"State", VNL);
*/
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));
quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
timersub (&now, &on->last_changed, &res);
timerstring (&res, duration, sizeof (duration));
vty_out (vty, "%-15s %6s/%-11s %-15s %-15s %s[%s]%s",
router_id, ospf6_neighbor_state_str[on->state],
duration, drouter, bdrouter, on->ospf6_if->interface->name,
ospf6_interface_state_str[on->ospf6_if->state],
VNL);
}
static void
ospf6_neighbor_show_detail (struct vty *vty, struct ospf6_neighbor *on)
{
char drouter[16], bdrouter[16];
char linklocal_addr[64], duration[32];
struct timeval now, res;
struct ospf6_lsa *lsa;
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));
quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
timersub (&now, &on->last_changed, &res);
timerstring (&res, duration, sizeof (duration));
vty_out (vty, " Neighbor %s%s", on->name,
VNL);
vty_out (vty, " Area %s via interface %s (ifindex %d)%s",
on->ospf6_if->area->name,
on->ospf6_if->interface->name,
on->ospf6_if->interface->ifindex,
VNL);
vty_out (vty, " His IfIndex: %d Link-local address: %s%s",
on->ifindex, linklocal_addr,
VNL);
vty_out (vty, " State %s for a duration of %s%s",
ospf6_neighbor_state_str[on->state], duration,
VNL);
vty_out (vty, " His choice of DR/BDR %s/%s, Priority %d%s",
drouter, bdrouter, on->priority,
VNL);
vty_out (vty, " DbDesc status: %s%s%s SeqNum: %#lx%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"), (u_long) ntohl (on->dbdesc_seqnum),
VNL);
vty_out (vty, " Summary-List: %d LSAs%s", on->summary_list->count,
VNL);
for (lsa = ospf6_lsdb_head (on->summary_list); lsa;
lsa = ospf6_lsdb_next (lsa))
vty_out (vty, " %s%s", lsa->name, VNL);
vty_out (vty, " Request-List: %d LSAs%s", on->request_list->count,
VNL);
for (lsa = ospf6_lsdb_head (on->request_list); lsa;
lsa = ospf6_lsdb_next (lsa))
vty_out (vty, " %s%s", lsa->name, VNL);
vty_out (vty, " Retrans-List: %d LSAs%s", on->retrans_list->count,
VNL);
for (lsa = ospf6_lsdb_head (on->retrans_list); lsa;
lsa = ospf6_lsdb_next (lsa))
vty_out (vty, " %s%s", lsa->name, VNL);
timerclear (&res);
if (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]%s",
on->dbdesc_list->count, duration,
(on->thread_send_dbdesc ? "on" : "off"),
VNL);
for (lsa = ospf6_lsdb_head (on->dbdesc_list); lsa;
lsa = ospf6_lsdb_next (lsa))
vty_out (vty, " %s%s", lsa->name, VNL);
timerclear (&res);
if (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]%s",
on->request_list->count, duration,
(on->thread_send_lsreq ? "on" : "off"),
VNL);
for (lsa = ospf6_lsdb_head (on->request_list); lsa;
lsa = ospf6_lsdb_next (lsa))
vty_out (vty, " %s%s", lsa->name, VNL);
timerclear (&res);
if (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]%s",
on->lsupdate_list->count, duration,
(on->thread_send_lsupdate ? "on" : "off"),
VNL);
for (lsa = ospf6_lsdb_head (on->lsupdate_list); lsa;
lsa = ospf6_lsdb_next (lsa))
vty_out (vty, " %s%s", lsa->name, VNL);
timerclear (&res);
if (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]%s",
on->lsack_list->count, duration,
(on->thread_send_lsack ? "on" : "off"),
VNL);
for (lsa = ospf6_lsdb_head (on->lsack_list); lsa;
lsa = ospf6_lsdb_next (lsa))
vty_out (vty, " %s%s", lsa->name, VNL);
}
DEFUN (show_ipv6_ospf6_neighbor,
show_ipv6_ospf6_neighbor_cmd,
"show ipv6 ospf6 neighbor",
SHOW_STR
IP6_STR
OSPF6_STR
"Neighbor list\n"
)
{
struct ospf6_neighbor *on;
struct ospf6_interface *oi;
struct ospf6_area *oa;
struct listnode *i, *j, *k;
void (*showfunc) (struct vty *, struct ospf6_neighbor *);
OSPF6_CMD_CHECK_RUNNING ();
showfunc = ospf6_neighbor_show;
if (argc)
{
if (! strncmp (argv[0], "de", 2))
showfunc = ospf6_neighbor_show_detail;
else if (! strncmp (argv[0], "dr", 2))
showfunc = ospf6_neighbor_show_drchoice;
}
if (showfunc == ospf6_neighbor_show)
vty_out (vty, "%-15s %3s %11s %6s/%-12s %11s %s[%s]%s",
"Neighbor ID", "Pri", "DeadTime", "State", "IfState", "Duration",
"I/F", "State", VNL);
else if (showfunc == ospf6_neighbor_show_drchoice)
vty_out (vty, "%-15s %6s/%-11s %-15s %-15s %s[%s]%s",
"RouterID", "State", "Duration", "DR", "BDR", "I/F",
"State", VNL);
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))
(*showfunc) (vty, on);
return CMD_SUCCESS;
}
ALIAS (show_ipv6_ospf6_neighbor,
show_ipv6_ospf6_neighbor_detail_cmd,
"show ipv6 ospf6 neighbor (detail|drchoice)",
SHOW_STR
IP6_STR
OSPF6_STR
"Neighbor list\n"
"Display details\n"
"Display DR choices\n"
)
DEFUN (show_ipv6_ospf6_neighbor_one,
show_ipv6_ospf6_neighbor_one_cmd,
"show ipv6 ospf6 neighbor A.B.C.D",
SHOW_STR
IP6_STR
OSPF6_STR
"Neighbor list\n"
"Specify Router-ID as IPv4 address notation\n"
)
{
struct ospf6_neighbor *on;
struct ospf6_interface *oi;
struct ospf6_area *oa;
struct listnode *i, *j, *k;
void (*showfunc) (struct vty *, struct ospf6_neighbor *);
u_int32_t router_id;
OSPF6_CMD_CHECK_RUNNING ();
showfunc = ospf6_neighbor_show_detail;
if ((inet_pton (AF_INET, argv[0], &router_id)) != 1)
{
vty_out (vty, "Router-ID is not parsable: %s%s", argv[0],
VNL);
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))
(*showfunc) (vty, on);
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_detail_cmd);
install_element (ENABLE_NODE, &show_ipv6_ospf6_neighbor_cmd);
install_element (ENABLE_NODE, &show_ipv6_ospf6_neighbor_detail_cmd);
}
DEFUN (debug_ospf6_neighbor,
debug_ospf6_neighbor_cmd,
"debug ospf6 neighbor",
DEBUG_STR
OSPF6_STR
"Debug OSPFv3 Neighbor\n"
)
{
unsigned char level = 0;
if (argc)
{
if (! strncmp (argv[0], "s", 1))
level = OSPF6_DEBUG_NEIGHBOR_STATE;
if (! strncmp (argv[0], "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;
}
ALIAS (debug_ospf6_neighbor,
debug_ospf6_neighbor_detail_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"
)
DEFUN (no_debug_ospf6_neighbor,
no_debug_ospf6_neighbor_cmd,
"no debug ospf6 neighbor",
NO_STR
DEBUG_STR
OSPF6_STR
"Debug OSPFv3 Neighbor\n"
)
{
unsigned char level = 0;
if (argc)
{
if (! strncmp (argv[0], "s", 1))
level = OSPF6_DEBUG_NEIGHBOR_STATE;
if (! strncmp (argv[0], "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;
}
ALIAS (no_debug_ospf6_neighbor,
no_debug_ospf6_neighbor_detail_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
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%s", VNL);
else if (IS_OSPF6_DEBUG_NEIGHBOR (STATE))
vty_out (vty, "debug ospf6 neighbor state%s", VNL);
else if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT))
vty_out (vty, "debug ospf6 neighbor event%s", VNL);
return 0;
}
void
install_element_ospf6_debug_neighbor (void)
{
install_element (ENABLE_NODE, &debug_ospf6_neighbor_cmd);
install_element (ENABLE_NODE, &debug_ospf6_neighbor_detail_cmd);
install_element (ENABLE_NODE, &no_debug_ospf6_neighbor_cmd);
install_element (ENABLE_NODE, &no_debug_ospf6_neighbor_detail_cmd);
install_element (CONFIG_NODE, &debug_ospf6_neighbor_cmd);
install_element (CONFIG_NODE, &debug_ospf6_neighbor_detail_cmd);
install_element (CONFIG_NODE, &no_debug_ospf6_neighbor_cmd);
install_element (CONFIG_NODE, &no_debug_ospf6_neighbor_detail_cmd);
}