mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-10-30 17:34:50 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			392 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			392 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * 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;
 | |
| }
 | |
| 
 | 
