mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-05-23 19:07:17 +00:00

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>
1014 lines
29 KiB
C
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);
|
|
}
|
|
|
|
|
|
|