summaryrefslogtreecommitdiff
path: root/ospf6d/ospf6_nsm.c
diff options
context:
space:
mode:
authorpaul <paul>2002-12-13 20:15:29 +0000
committerpaul <paul>2002-12-13 20:15:29 +0000
commit718e3744195351130f4ce7dbe0613f4b3e23df93 (patch)
treebac2ad39971cd43f31241ef123bd4e470f695ac9 /ospf6d/ospf6_nsm.c
Initial revision
Diffstat (limited to 'ospf6d/ospf6_nsm.c')
-rw-r--r--ospf6d/ospf6_nsm.c391
1 files changed, 391 insertions, 0 deletions
diff --git a/ospf6d/ospf6_nsm.c b/ospf6d/ospf6_nsm.c
new file mode 100644
index 00000000..aa08d40b
--- /dev/null
+++ b/ospf6d/ospf6_nsm.c
@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 1999 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 "ospf6d.h"
+
+static int
+nbs_full_change (struct ospf6_interface *ospf6_interface)
+{
+ CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, ospf6_interface);
+ return 0;
+}
+
+static int
+nbs_change (state_t nbs_next, char *reason, struct ospf6_neighbor *o6n)
+{
+ state_t nbs_previous;
+
+ nbs_previous = o6n->state;
+ o6n->state = nbs_next;
+
+ if (nbs_previous == nbs_next)
+ return 0;
+
+ /* statistics */
+ o6n->ospf6_stat_state_changed++;
+ gettimeofday (&o6n->last_changed, NULL);
+
+ /* log */
+ if (IS_OSPF6_DUMP_NEIGHBOR)
+ {
+ if (reason)
+ zlog_info ("Neighbor status change %s: [%s]->[%s](%s)",
+ o6n->str,
+ ospf6_neighbor_state_string[nbs_previous],
+ ospf6_neighbor_state_string[nbs_next],
+ reason);
+ else
+ zlog_info ("Neighbor status change %s: [%s]->[%s]",
+ o6n->str,
+ ospf6_neighbor_state_string[nbs_previous],
+ ospf6_neighbor_state_string[nbs_next]);
+ }
+
+ if (nbs_previous == NBS_FULL || nbs_next == NBS_FULL)
+ nbs_full_change (o6n->ospf6_interface);
+
+ /* check for LSAs that already reached MaxAge */
+ if ((nbs_previous == NBS_EXCHANGE || nbs_previous == NBS_LOADING) &&
+ (nbs_next != NBS_EXCHANGE && nbs_next != NBS_LOADING))
+ {
+ ospf6_maxage_remover ();
+ }
+
+ CALL_CHANGE_HOOK (&neighbor_hook, o6n);
+
+ return 0;
+}
+
+/* RFC2328 section 10.4 */
+int
+need_adjacency (struct ospf6_neighbor *o6n)
+{
+
+ if (o6n->ospf6_interface->state == IFS_PTOP)
+ return 1;
+ if (o6n->ospf6_interface->state == IFS_DR)
+ return 1;
+ if (o6n->ospf6_interface->state == IFS_BDR)
+ return 1;
+ if (o6n->router_id == o6n->ospf6_interface->dr)
+ return 1;
+ if (o6n->router_id == o6n->ospf6_interface->bdr)
+ return 1;
+
+ return 0;
+}
+
+int
+hello_received (struct thread *thread)
+{
+ struct ospf6_neighbor *o6n;
+
+ o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+ assert (o6n);
+
+ if (IS_OSPF6_DUMP_NEIGHBOR)
+ zlog_info ("Neighbor Event %s: *HelloReceived*", o6n->str);
+
+ if (o6n->inactivity_timer)
+ thread_cancel (o6n->inactivity_timer);
+
+ o6n->inactivity_timer = thread_add_timer (master, inactivity_timer, o6n,
+ o6n->ospf6_interface->dead_interval);
+ if (o6n->state <= NBS_DOWN)
+ nbs_change (NBS_INIT, "HelloReceived", o6n);
+ return 0;
+}
+
+int
+twoway_received (struct thread *thread)
+{
+ struct ospf6_neighbor *o6n;
+
+ o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+ assert (o6n);
+
+ if (o6n->state > NBS_INIT)
+ return 0;
+
+ if (IS_OSPF6_DUMP_NEIGHBOR)
+ zlog_info ("Neighbor Event %s: *2Way-Received*", o6n->str);
+
+ thread_add_event (master, neighbor_change, o6n->ospf6_interface, 0);
+
+ if (!need_adjacency (o6n))
+ {
+ nbs_change (NBS_TWOWAY, "No Need Adjacency", o6n);
+ return 0;
+ }
+ else
+ nbs_change (NBS_EXSTART, "Need Adjacency", o6n);
+
+ DD_MSBIT_SET (o6n->dbdesc_bits);
+ DD_MBIT_SET (o6n->dbdesc_bits);
+ DD_IBIT_SET (o6n->dbdesc_bits);
+
+ if (o6n->thread_send_dbdesc)
+ thread_cancel (o6n->thread_send_dbdesc);
+ o6n->thread_send_dbdesc =
+ thread_add_event (master, ospf6_send_dbdesc, o6n, 0);
+ if (o6n->thread_rxmt_dbdesc)
+ thread_cancel (o6n->thread_rxmt_dbdesc);
+ o6n->thread_rxmt_dbdesc = (struct thread *) NULL;
+
+ return 0;
+}
+
+int
+negotiation_done (struct thread *thread)
+{
+ struct ospf6_neighbor *o6n;
+
+ o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+ assert (o6n);
+
+ if (o6n->state != NBS_EXSTART)
+ return 0;
+
+ if (IS_OSPF6_DUMP_NEIGHBOR)
+ zlog_info ("Neighbor Event %s: *NegotiationDone*", o6n->str);
+
+ nbs_change (NBS_EXCHANGE, "NegotiationDone", o6n);
+ DD_IBIT_CLEAR (o6n->dbdesc_bits);
+
+ return 0;
+}
+
+int
+exchange_done (struct thread *thread)
+{
+ struct ospf6_neighbor *o6n;
+
+ o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+ assert (o6n);
+
+ if (o6n->state != NBS_EXCHANGE)
+ return 0;
+
+ if (o6n->thread_rxmt_dbdesc)
+ thread_cancel (o6n->thread_rxmt_dbdesc);
+ o6n->thread_rxmt_dbdesc = (struct thread *) NULL;
+
+ if (IS_OSPF6_DUMP_NEIGHBOR)
+ zlog_info ("Neighbor Event %s: *ExchangeDone*", o6n->str);
+
+ ospf6_lsdb_remove_all (o6n->dbdesc_list);
+
+ thread_add_timer (master, ospf6_neighbor_last_dbdesc_release, o6n,
+ o6n->ospf6_interface->dead_interval);
+
+ if (o6n->request_list->count == 0)
+ nbs_change (NBS_FULL, "Requestlist Empty", o6n);
+ else
+ {
+ thread_add_event (master, ospf6_send_lsreq, o6n, 0);
+ nbs_change (NBS_LOADING, "Requestlist Not Empty", o6n);
+ }
+ return 0;
+}
+
+int
+loading_done (struct thread *thread)
+{
+ struct ospf6_neighbor *o6n;
+
+ o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+ assert (o6n);
+
+ if (o6n->state != NBS_LOADING)
+ return 0;
+
+ if (IS_OSPF6_DUMP_NEIGHBOR)
+ zlog_info ("Neighbor Event %s: *LoadingDone*", o6n->str);
+
+ assert (o6n->request_list->count == 0);
+
+ nbs_change (NBS_FULL, "LoadingDone", o6n);
+
+ return 0;
+}
+
+int
+adj_ok (struct thread *thread)
+{
+ struct ospf6_neighbor *o6n;
+
+ o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+ assert (o6n);
+
+ if (IS_OSPF6_DUMP_NEIGHBOR)
+ zlog_info ("Neighbor Event %s: *AdjOK?*", o6n->str);
+
+ if (o6n->state == NBS_TWOWAY)
+ {
+ if (!need_adjacency (o6n))
+ {
+ nbs_change (NBS_TWOWAY, "No Need Adjacency", o6n);
+ return 0;
+ }
+ else
+ nbs_change (NBS_EXSTART, "Need Adjacency", o6n);
+
+ DD_MSBIT_SET (o6n->dbdesc_bits);
+ DD_MBIT_SET (o6n->dbdesc_bits);
+ DD_IBIT_SET (o6n->dbdesc_bits);
+
+ if (o6n->thread_send_dbdesc)
+ thread_cancel (o6n->thread_send_dbdesc);
+ o6n->thread_send_dbdesc =
+ thread_add_event (master, ospf6_send_dbdesc, o6n, 0);
+
+ return 0;
+ }
+
+ if (o6n->state >= NBS_EXSTART)
+ {
+ if (need_adjacency (o6n))
+ return 0;
+ else
+ {
+ nbs_change (NBS_TWOWAY, "No Need Adjacency", o6n);
+ ospf6_neighbor_lslist_clear (o6n);
+ }
+ }
+ return 0;
+}
+
+int
+seqnumber_mismatch (struct thread *thread)
+{
+ struct ospf6_neighbor *o6n;
+
+ o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+ assert (o6n);
+
+ if (o6n->state < NBS_EXCHANGE)
+ return 0;
+
+ /* statistics */
+ o6n->ospf6_stat_seqnum_mismatch++;
+
+ if (IS_OSPF6_DUMP_NEIGHBOR)
+ zlog_info ("Neighbor Event %s: *SeqNumberMismatch*", o6n->str);
+
+ nbs_change (NBS_EXSTART, "SeqNumberMismatch", o6n);
+
+ DD_MSBIT_SET (o6n->dbdesc_bits);
+ DD_MBIT_SET (o6n->dbdesc_bits);
+ DD_IBIT_SET (o6n->dbdesc_bits);
+ ospf6_neighbor_lslist_clear (o6n);
+
+ if (o6n->thread_send_dbdesc)
+ thread_cancel (o6n->thread_send_dbdesc);
+ o6n->thread_send_dbdesc =
+ thread_add_event (master, ospf6_send_dbdesc, o6n, 0);
+
+ return 0;
+}
+
+int
+bad_lsreq (struct thread *thread)
+{
+ struct ospf6_neighbor *o6n;
+
+ o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+ assert (o6n);
+
+ if (o6n->state < NBS_EXCHANGE)
+ return 0;
+
+ /* statistics */
+ o6n->ospf6_stat_bad_lsreq++;
+
+ if (IS_OSPF6_DUMP_NEIGHBOR)
+ zlog_info ("Neighbor Event %s: *BadLSReq*", o6n->str);
+
+ nbs_change (NBS_EXSTART, "BadLSReq", o6n);
+
+ DD_MSBIT_SET (o6n->dbdesc_bits);
+ DD_MBIT_SET (o6n->dbdesc_bits);
+ DD_IBIT_SET (o6n->dbdesc_bits);
+ ospf6_neighbor_lslist_clear (o6n);
+
+ if (o6n->thread_send_dbdesc)
+ thread_cancel (o6n->thread_send_dbdesc);
+ o6n->thread_send_dbdesc =
+ thread_add_event (master, ospf6_send_dbdesc, o6n, 0);
+
+ return 0;
+}
+
+int
+oneway_received (struct thread *thread)
+{
+ struct ospf6_neighbor *o6n;
+
+ o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+ assert (o6n);
+
+ if (o6n->state < NBS_TWOWAY)
+ return 0;
+
+ /* statistics */
+ o6n->ospf6_stat_oneway_received++;
+
+ if (IS_OSPF6_DUMP_NEIGHBOR)
+ zlog_info ("Neighbor Event %s: *1Way-Received*", o6n->str);
+
+ nbs_change (NBS_INIT, "1Way-Received", o6n);
+
+ thread_add_event (master, neighbor_change, o6n->ospf6_interface, 0);
+
+ ospf6_neighbor_thread_cancel_all (o6n);
+ ospf6_neighbor_lslist_clear (o6n);
+ return 0;
+}
+
+int
+inactivity_timer (struct thread *thread)
+{
+ struct ospf6_neighbor *o6n;
+
+ o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+ assert (o6n);
+
+ /* statistics */
+ o6n->ospf6_stat_inactivity_timer++;
+
+ if (IS_OSPF6_DUMP_NEIGHBOR)
+ zlog_info ("Neighbor Event %s: *InactivityTimer*", o6n->str);
+
+ o6n->inactivity_timer = NULL;
+ o6n->dr = o6n->bdr = o6n->prevdr = o6n->prevbdr = 0;
+ nbs_change (NBS_DOWN, "InactivityTimer", o6n);
+
+ thread_add_event (master, neighbor_change, o6n->ospf6_interface, 0);
+
+ listnode_delete (o6n->ospf6_interface->neighbor_list, o6n);
+ ospf6_neighbor_delete (o6n);
+
+ return 0;
+}
+