1 /*
2  * IS-IS Rout(e)ing protocol - isisd.c
3  *
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 "pmacct.h"
24 #include "isis.h"
25 
26 #include "hash.h"
27 #include "prefix.h"
28 #include "table.h"
29 
30 #include "dict.h"
31 #include "thread.h"
32 #include "isis_constants.h"
33 #include "isis_common.h"
34 #include "isis_circuit.h"
35 #include "isis_flags.h"
36 #include "isisd.h"
37 #include "isis_misc.h"
38 #include "isis_tlv.h"
39 #include "isis_lsp.h"
40 #include "isis_constants.h"
41 #include "isis_adjacency.h"
42 #include "isis_dynhn.h"
43 #include "isis_pdu.h"
44 #include "isis_spf.h"
45 #include "isis_route.h"
46 #include "isis_csm.h"
47 
48 extern struct thread_master *master;
49 
50 void isis_new(unsigned long);
51 struct isis_area *isis_area_create(void);
52 int isis_area_get(const char *);
53 int isis_area_destroy(const char *);
54 
55 void
isis_new(unsigned long process_id)56 isis_new (unsigned long process_id)
57 {
58   isis = calloc(1, sizeof (struct isis));
59   /*
60    * Default values
61    */
62   isis->max_area_addrs = 3;
63 
64   isis->process_id = process_id;
65   isis->area_list = pm_list_new ();
66   isis->init_circ_list = pm_list_new ();
67   isis->uptime = time (NULL);
68   isis->nexthops = pm_list_new ();
69   isis->nexthops6 = pm_list_new ();
70   /*
71    * uncomment the next line for full debugs
72    */
73   /* isis->debugs = 0xFFFF; */
74 }
75 
76 void
isis_init()77 isis_init ()
78 {
79   isis_new (0);
80 }
81 
82 struct isis_area *
isis_area_create()83 isis_area_create ()
84 {
85   struct isis_area *area;
86 
87   area = calloc(1, sizeof (struct isis_area));
88 
89   /*
90    * The first instance is level-1-2 rest are level-1, unless otherwise
91    * configured
92    */
93   if (pm_listcount (isis->area_list) > 0)
94     area->is_type = IS_LEVEL_1;
95   else
96     area->is_type = IS_LEVEL_1_AND_2;
97   /*
98    * intialize the databases
99    */
100   area->lspdb[0] = lsp_db_init ();
101   area->lspdb[1] = lsp_db_init ();
102 
103   spftree_area_init (area);
104   area->route_table[0] = route_table_init ();
105   area->route_table[1] = route_table_init ();
106   area->route_table6[0] = route_table_init ();
107   area->route_table6[1] = route_table_init ();
108   area->circuit_list = pm_list_new ();
109   area->area_addrs = pm_list_new ();
110   flags_initialize (&area->flags);
111   /*
112    * Default values
113    */
114   area->max_lsp_lifetime[0] = MAX_AGE;	/* 1200 */
115   area->max_lsp_lifetime[1] = MAX_AGE;	/* 1200 */
116   area->lsp_gen_interval[0] = LSP_GEN_INTERVAL_DEFAULT;
117   area->lsp_gen_interval[1] = LSP_GEN_INTERVAL_DEFAULT;
118   area->lsp_refresh[0] = MAX_LSP_GEN_INTERVAL;	/* 900 */
119   area->lsp_refresh[1] = MAX_LSP_GEN_INTERVAL;	/* 900 */
120   area->min_spf_interval[0] = MINIMUM_SPF_INTERVAL;
121   area->min_spf_interval[1] = MINIMUM_SPF_INTERVAL;
122   area->dynhostname = 1;
123   area->oldmetric = 1;
124   area->lsp_frag_threshold = 90;
125 
126   /* FIXME: Think of a better way... */
127   area->min_bcast_mtu = 1497;
128 
129   return area;
130 }
131 
132 struct isis_area *
isis_area_lookup(const char * area_tag)133 isis_area_lookup (const char *area_tag)
134 {
135   struct isis_area *area;
136   struct pm_listnode *node;
137 
138   for (PM_ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
139     if ((area->area_tag == NULL && area_tag == NULL) ||
140 	(area->area_tag && area_tag
141 	 && strcmp (area->area_tag, area_tag) == 0))
142     return area;
143 
144   return NULL;
145 }
146 
147 int
isis_area_get(const char * area_tag)148 isis_area_get (const char *area_tag)
149 {
150   struct isis_area *area;
151 
152   area = isis_area_lookup (area_tag);
153 
154   if (area)
155     {
156       return FALSE;
157     }
158 
159   area = isis_area_create ();
160   area->area_tag = strdup (area_tag);
161   pm_listnode_add (isis->area_list, area);
162 
163   Log(LOG_DEBUG, "DEBUG ( %s/core/ISIS ): New IS-IS area instance %s\n", config.name, area->area_tag);
164 
165   return FALSE;
166 }
167 
168 int
isis_area_destroy(const char * area_tag)169 isis_area_destroy (const char *area_tag)
170 {
171   struct isis_area *area;
172   struct pm_listnode *node, *nnode;
173   struct isis_circuit *circuit;
174 
175   area = isis_area_lookup (area_tag);
176 
177   if (area == NULL)
178     {
179       Log(LOG_WARNING, "WARN ( %s/core/ISIS ): Can't find ISIS instance %s\n", config.name, area_tag);
180       return TRUE;
181     }
182 
183   if (area->circuit_list)
184     {
185       for (PM_ALL_LIST_ELEMENTS (area->circuit_list, node, nnode, circuit))
186 	{
187 	  /* The fact that it's in circuit_list means that it was configured */
188 	  isis_csm_state_change (ISIS_DISABLE, circuit, area);
189 	  isis_circuit_down (circuit);
190 	  isis_circuit_deconfigure (circuit, area);
191 	}
192 
193       pm_list_delete (area->circuit_list);
194     }
195   pm_listnode_delete (isis->area_list, area);
196 
197   if (area->t_remove_aged)
198     thread_cancel (area->t_remove_aged);
199 
200   THREAD_TIMER_OFF (area->spftree[0]->t_spf);
201   THREAD_TIMER_OFF (area->spftree[1]->t_spf);
202 
203   free(area);
204 
205   isis->sysid_set=0;
206 
207   return FALSE;
208 }
209 
210 int
area_net_title(struct isis_area * area,const char * net_title)211 area_net_title (struct isis_area *area, const char *net_title)
212 {
213   struct area_addr *addr;
214   struct area_addr *addrp;
215   struct pm_listnode *node;
216 
217   char buff[255];
218 
219   if (!area)
220     {
221       Log(LOG_WARNING, "WARN ( %s/core/ISIS ): Can't find ISIS instance\n", config.name);
222       return TRUE;
223     }
224 
225   /* We check that we are not over the maximal number of addresses */
226   if (pm_listcount (area->area_addrs) >= isis->max_area_addrs)
227     {
228       Log(LOG_WARNING, "WARN ( %s/core/ISIS ): Maximum of area addresses (%d) already reached\n",
229 	       config.name, isis->max_area_addrs);
230       return TRUE;
231     }
232 
233   addr = calloc(1, sizeof (struct area_addr));
234   addr->addr_len = dotformat2buff (buff, net_title);
235   memcpy (addr->area_addr, buff, addr->addr_len);
236   if (addr->addr_len < 8 || addr->addr_len > 20)
237     {
238       Log(LOG_WARNING, "WARN ( %s/core/ISIS ): area address must be at least 8..20 octets long (%d)\n",
239 		 config.name, addr->addr_len);
240       free(addr);
241       return TRUE;
242     }
243 
244   if (isis->sysid_set == 0)
245     {
246       /*
247        * First area address - get the SystemID for this router
248        */
249       memcpy (isis->sysid, GETSYSID (addr, ISIS_SYS_ID_LEN), ISIS_SYS_ID_LEN);
250       isis->sysid_set = 1;
251       Log(LOG_DEBUG, "DEBUG ( %s/core/ISIS ): Router has SystemID %s\n", config.name, sysid_print (isis->sysid));
252     }
253   else
254     {
255       /*
256        * Check that the SystemID portions match
257        */
258       if (memcmp (isis->sysid, GETSYSID (addr, ISIS_SYS_ID_LEN),
259 		  ISIS_SYS_ID_LEN))
260 	{
261 	  Log(LOG_WARNING, "WARN ( %s/core/ISIS ): System ID must not change when defining additional area addresses\n", config.name);
262 	  free(addr);
263 	  return TRUE;
264 	}
265 
266       /* now we see that we don't already have this address */
267       for (PM_ALL_LIST_ELEMENTS_RO (area->area_addrs, node, addrp))
268 	{
269 	  if ((addrp->addr_len + ISIS_SYS_ID_LEN + 1) != (addr->addr_len))
270 	    continue;
271 	  if (!memcmp (addrp->area_addr, addr->area_addr, addr->addr_len))
272 	    {
273 	      free(addr);
274 	      return FALSE;	/* silent fail */
275 	    }
276 	}
277 
278     }
279   /*
280    * Forget the systemID part of the address
281    */
282   addr->addr_len -= (ISIS_SYS_ID_LEN + 1);
283   pm_listnode_add (area->area_addrs, addr);
284 
285   /* Only now we can safely generate our LSPs for this area */
286   if (pm_listcount (area->area_addrs) > 0)
287     {
288       lsp_l1_generate (area);
289       lsp_l2_generate (area);
290     }
291 
292   return FALSE;
293 }
294 
295 int
area_clear_net_title(struct isis_area * area,const char * net_title)296 area_clear_net_title (struct isis_area *area, const char *net_title)
297 {
298   struct area_addr addr, *addrp = NULL;
299   struct pm_listnode *node;
300   char buff[255];
301 
302   if (!area)
303     {
304       Log(LOG_WARNING, "WARN ( %s/core/ISIS ): Can't find ISIS instance\n", config.name);
305       return TRUE;
306     }
307 
308   addr.addr_len = dotformat2buff (buff, net_title);
309   if (addr.addr_len < 8 || addr.addr_len > 20)
310     {
311       Log(LOG_WARNING, "WARN ( %s/core/ISIS ): Unsupported area address length %d, should be 8...20\n", config.name, addr.addr_len);
312       return TRUE;
313     }
314 
315   memcpy (addr.area_addr, buff, (int) addr.addr_len);
316 
317   for (PM_ALL_LIST_ELEMENTS_RO (area->area_addrs, node, addrp))
318     if (addrp->addr_len == addr.addr_len &&
319 	!memcmp (addrp->area_addr, addr.area_addr, addr.addr_len))
320     break;
321 
322   if (!addrp)
323     {
324       Log(LOG_WARNING, "WARN ( %s/core/ISIS ): No area address %s for area %s\n",
325 		config.name, net_title, area->area_tag);
326       return TRUE;
327     }
328 
329   pm_listnode_delete (area->area_addrs, addrp);
330 
331   return FALSE;
332 }
333