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