Import Upstream version 1.2.2
[quagga-debian.git] / isisd / isis_csm.c
1 /*
2  * IS-IS Rout(e)ing protocol - isis_csm.c
3  *                             IS-IS circuit state machine
4  * Copyright (C) 2001,2002    Sampo Saaristo
5  *                            Tampere University of Technology      
6  *                            Institute of Communications Engineering
7  *
8  * This program is free software; you can redistribute it and/or modify it 
9  * under the terms of the GNU General Public Licenseas published by the Free 
10  * Software Foundation; either version 2 of the License, or (at your option) 
11  * any later version.
12  *
13  * This program is distributed in the hope that it will be useful,but WITHOUT 
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
16  * more details.
17  *
18  * You should have received a copy of the GNU General Public License along 
19  * with this program; if not, write to the Free Software Foundation, Inc., 
20  * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  */
22
23 #include <zebra.h>
24
25 #include "log.h"
26 #include "memory.h"
27 #include "if.h"
28 #include "linklist.h"
29 #include "command.h"
30 #include "thread.h"
31 #include "hash.h"
32 #include "prefix.h"
33 #include "stream.h"
34
35 #include "isisd/dict.h"
36 #include "isisd/include-netbsd/iso.h"
37 #include "isisd/isis_constants.h"
38 #include "isisd/isis_common.h"
39 #include "isisd/isis_flags.h"
40 #include "isisd/isis_circuit.h"
41 #include "isisd/isis_tlv.h"
42 #include "isisd/isis_lsp.h"
43 #include "isisd/isis_pdu.h"
44 #include "isisd/isis_network.h"
45 #include "isisd/isis_misc.h"
46 #include "isisd/isis_constants.h"
47 #include "isisd/isis_adjacency.h"
48 #include "isisd/isis_dr.h"
49 #include "isisd/isisd.h"
50 #include "isisd/isis_csm.h"
51 #include "isisd/isis_events.h"
52
53 extern struct isis *isis;
54
55 static const char *csm_statestr[] = {
56   "C_STATE_NA",
57   "C_STATE_INIT",
58   "C_STATE_CONF",
59   "C_STATE_UP"
60 };
61
62 #define STATE2STR(S) csm_statestr[S]
63
64 static const char *csm_eventstr[] = {
65   "NO_STATE",
66   "ISIS_ENABLE",
67   "IF_UP_FROM_Z",
68   "ISIS_DISABLE",
69   "IF_DOWN_FROM_Z",
70 };
71
72 #define EVENT2STR(E) csm_eventstr[E]
73
74 struct isis_circuit *
75 isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg)
76 {
77   int old_state;
78
79   old_state = circuit ? circuit->state : C_STATE_NA;
80   if (isis->debugs & DEBUG_EVENTS)
81     zlog_debug ("CSM_EVENT: %s", EVENT2STR (event));
82
83   switch (old_state)
84     {
85     case C_STATE_NA:
86       if (circuit)
87         zlog_warn ("Non-null circuit while state C_STATE_NA");
88       assert (circuit == NULL);
89       switch (event)
90         {
91         case ISIS_ENABLE:
92           circuit = isis_circuit_new ();
93           isis_circuit_configure (circuit, (struct isis_area *) arg);
94           circuit->state = C_STATE_CONF;
95           break;
96         case IF_UP_FROM_Z:
97           circuit = isis_circuit_new ();
98           isis_circuit_if_add (circuit, (struct interface *) arg);
99           listnode_add (isis->init_circ_list, circuit);
100           circuit->state = C_STATE_INIT;
101           break;
102         case ISIS_DISABLE:
103           zlog_warn ("circuit already disabled");
104           break;
105         case IF_DOWN_FROM_Z:
106           zlog_warn ("circuit already disconnected");
107           break;
108         }
109       break;
110     case C_STATE_INIT:
111       assert (circuit);
112       switch (event)
113         {
114         case ISIS_ENABLE:
115           isis_circuit_configure (circuit, (struct isis_area *) arg);
116           if (isis_circuit_up (circuit) != ISIS_OK)
117             {
118               isis_circuit_deconfigure (circuit, (struct isis_area *) arg);
119               break;
120             }
121           circuit->state = C_STATE_UP;
122           isis_event_circuit_state_change (circuit, circuit->area, 1);
123           listnode_delete (isis->init_circ_list, circuit);
124           break;
125         case IF_UP_FROM_Z:
126           assert (circuit);
127           zlog_warn ("circuit already connected");
128           break;
129         case ISIS_DISABLE:
130           zlog_warn ("circuit already disabled");
131           break;
132         case IF_DOWN_FROM_Z:
133           isis_circuit_if_del (circuit, (struct interface *) arg);
134           listnode_delete (isis->init_circ_list, circuit);
135           isis_circuit_del (circuit);
136           circuit = NULL;
137           break;
138         }
139       break;
140     case C_STATE_CONF:
141       assert (circuit);
142       switch (event)
143         {
144         case ISIS_ENABLE:
145           zlog_warn ("circuit already enabled");
146           break;
147         case IF_UP_FROM_Z:
148           isis_circuit_if_add (circuit, (struct interface *) arg);
149           if (isis_circuit_up (circuit) != ISIS_OK)
150             {
151               zlog_err("Could not bring up %s because of invalid config.",
152                        circuit->interface->name);
153               zlog_err("Clearing config for %s. Please re-examine it.",
154                        circuit->interface->name);
155               if (circuit->ip_router)
156                 {
157                   circuit->ip_router = 0;
158                   circuit->area->ip_circuits--;
159                 }
160               if (circuit->ipv6_router)
161                 {
162                   circuit->ipv6_router = 0;
163                   circuit->area->ipv6_circuits--;
164                 }
165               circuit_update_nlpids(circuit);
166               isis_circuit_deconfigure(circuit, circuit->area);
167               listnode_add (isis->init_circ_list, circuit);
168               circuit->state = C_STATE_INIT;
169               break;
170             }
171           circuit->state = C_STATE_UP;
172           isis_event_circuit_state_change (circuit, circuit->area, 1);
173           break;
174         case ISIS_DISABLE:
175           isis_circuit_deconfigure (circuit, (struct isis_area *) arg);
176           isis_circuit_del (circuit);
177           circuit = NULL;
178           break;
179         case IF_DOWN_FROM_Z:
180           zlog_warn ("circuit already disconnected");
181           break;
182         }
183       break;
184     case C_STATE_UP:
185       assert (circuit);
186       switch (event)
187         {
188         case ISIS_ENABLE:
189           zlog_warn ("circuit already configured");
190           break;
191         case IF_UP_FROM_Z:
192           zlog_warn ("circuit already connected");
193           break;
194         case ISIS_DISABLE:
195           isis_circuit_down (circuit);
196           isis_circuit_deconfigure (circuit, (struct isis_area *) arg);
197           circuit->state = C_STATE_INIT;
198           isis_event_circuit_state_change (circuit,
199                                            (struct isis_area *)arg, 0);
200           listnode_add (isis->init_circ_list, circuit);
201           break;
202         case IF_DOWN_FROM_Z:
203           isis_circuit_down (circuit);
204           isis_circuit_if_del (circuit, (struct interface *) arg);
205           circuit->state = C_STATE_CONF;
206           isis_event_circuit_state_change (circuit, circuit->area, 0);
207           break;
208         }
209       break;
210
211     default:
212       zlog_warn ("Invalid circuit state %d", old_state);
213     }
214
215   if (isis->debugs & DEBUG_EVENTS)
216     zlog_debug ("CSM_STATE_CHANGE: %s -> %s ", STATE2STR (old_state),
217                 circuit ? STATE2STR (circuit->state) : STATE2STR (C_STATE_NA));
218
219   return circuit;
220 }