blob: f71794323e43d207176d4b265bb964526fcef7c0 [file] [log] [blame]
jardineb5d44e2003-12-23 08:09:43 +00001/*
2 * IS-IS Rout(e)ing protocol - isis_lsp.c
3 * LSP processing
4 *
5 * Copyright (C) 2001,2002 Sampo Saaristo
6 * Tampere University of Technology
7 * Institute of Communications Engineering
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public Licenseas published by the Free
11 * Software Foundation; either version 2 of the License, or (at your option)
12 * any later version.
13 *
14 * This program is distributed in the hope that it will be useful,but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
paul15935e92005-05-03 09:27:23 +000023
jardineb5d44e2003-12-23 08:09:43 +000024#include <zebra.h>
jardineb5d44e2003-12-23 08:09:43 +000025
26#include "linklist.h"
27#include "thread.h"
28#include "vty.h"
29#include "stream.h"
30#include "memory.h"
31#include "log.h"
32#include "prefix.h"
33#include "command.h"
34#include "hash.h"
35#include "if.h"
Jingjing Duan6a270cd2008-08-13 19:09:10 +010036#include "checksum.h"
Josh Bailey3f045a02012-03-24 08:35:20 -070037#include "md5.h"
jardineb5d44e2003-12-23 08:09:43 +000038
39#include "isisd/dict.h"
40#include "isisd/isis_constants.h"
41#include "isisd/isis_common.h"
Josh Bailey3f045a02012-03-24 08:35:20 -070042#include "isisd/isis_flags.h"
jardineb5d44e2003-12-23 08:09:43 +000043#include "isisd/isis_circuit.h"
44#include "isisd/isisd.h"
45#include "isisd/isis_tlv.h"
46#include "isisd/isis_lsp.h"
47#include "isisd/isis_pdu.h"
48#include "isisd/isis_dynhn.h"
49#include "isisd/isis_misc.h"
jardineb5d44e2003-12-23 08:09:43 +000050#include "isisd/isis_csm.h"
51#include "isisd/isis_adjacency.h"
52#include "isisd/isis_spf.h"
53
54#ifdef TOPOLOGY_GENERATE
55#include "spgrid.h"
56#endif
57
hasso73d1aea2004-09-24 10:45:28 +000058/* staticly assigned vars for printing purposes */
59char lsp_bits_string[200]; /* FIXME: enough ? */
60
Josh Bailey3f045a02012-03-24 08:35:20 -070061static int lsp_l1_refresh (struct thread *thread);
62static int lsp_l2_refresh (struct thread *thread);
63static int lsp_l1_refresh_pseudo (struct thread *thread);
64static int lsp_l2_refresh_pseudo (struct thread *thread);
65
hassof390d2c2004-09-10 20:48:21 +000066int
67lsp_id_cmp (u_char * id1, u_char * id2)
68{
jardineb5d44e2003-12-23 08:09:43 +000069 return memcmp (id1, id2, ISIS_SYS_ID_LEN + 2);
70}
71
72dict_t *
hassof390d2c2004-09-10 20:48:21 +000073lsp_db_init (void)
jardineb5d44e2003-12-23 08:09:43 +000074{
75 dict_t *dict;
hassof390d2c2004-09-10 20:48:21 +000076
77 dict = dict_create (DICTCOUNT_T_MAX, (dict_comp_t) lsp_id_cmp);
78
jardineb5d44e2003-12-23 08:09:43 +000079 return dict;
80}
81
82struct isis_lsp *
hassof390d2c2004-09-10 20:48:21 +000083lsp_search (u_char * id, dict_t * lspdb)
jardineb5d44e2003-12-23 08:09:43 +000084{
85 dnode_t *node;
86
hassof390d2c2004-09-10 20:48:21 +000087#ifdef EXTREME_DEBUG
jardineb5d44e2003-12-23 08:09:43 +000088 dnode_t *dn;
89
hasso529d65b2004-12-24 00:14:50 +000090 zlog_debug ("searching db");
hassof390d2c2004-09-10 20:48:21 +000091 for (dn = dict_first (lspdb); dn; dn = dict_next (lspdb, dn))
92 {
Josh Bailey3f045a02012-03-24 08:35:20 -070093 zlog_debug ("%s\t%pX", rawlspid_print ((u_char *) dnode_getkey (dn)),
hasso529d65b2004-12-24 00:14:50 +000094 dnode_get (dn));
hassof390d2c2004-09-10 20:48:21 +000095 }
jardineb5d44e2003-12-23 08:09:43 +000096#endif /* EXTREME DEBUG */
97
98 node = dict_lookup (lspdb, id);
hassof390d2c2004-09-10 20:48:21 +000099
jardineb5d44e2003-12-23 08:09:43 +0000100 if (node)
hassof390d2c2004-09-10 20:48:21 +0000101 return (struct isis_lsp *) dnode_get (node);
jardineb5d44e2003-12-23 08:09:43 +0000102
103 return NULL;
104}
105
hasso92365882005-01-18 13:53:33 +0000106static void
jardineb5d44e2003-12-23 08:09:43 +0000107lsp_clear_data (struct isis_lsp *lsp)
108{
109 if (!lsp)
110 return;
hassof390d2c2004-09-10 20:48:21 +0000111
Josh Bailey3f045a02012-03-24 08:35:20 -0700112 if (lsp->tlv_data.hostname)
113 isis_dynhn_remove (lsp->lsp_header->lsp_id);
114
hassof390d2c2004-09-10 20:48:21 +0000115 if (lsp->own_lsp)
116 {
117 if (lsp->tlv_data.nlpids)
Josh Bailey3f045a02012-03-24 08:35:20 -0700118 XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.nlpids);
hassof390d2c2004-09-10 20:48:21 +0000119 if (lsp->tlv_data.hostname)
Josh Bailey3f045a02012-03-24 08:35:20 -0700120 XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.hostname);
121 if (lsp->tlv_data.router_id)
122 XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.router_id);
hassof390d2c2004-09-10 20:48:21 +0000123 }
jardineb5d44e2003-12-23 08:09:43 +0000124
Josh Bailey3f045a02012-03-24 08:35:20 -0700125 free_tlvs (&lsp->tlv_data);
jardineb5d44e2003-12-23 08:09:43 +0000126}
127
hasso92365882005-01-18 13:53:33 +0000128static void
jardineb5d44e2003-12-23 08:09:43 +0000129lsp_destroy (struct isis_lsp *lsp)
130{
Josh Bailey3f045a02012-03-24 08:35:20 -0700131 struct listnode *cnode, *lnode, *lnnode;
132 struct isis_lsp *lsp_in_list;
133 struct isis_circuit *circuit;
134
jardineb5d44e2003-12-23 08:09:43 +0000135 if (!lsp)
136 return;
hassof390d2c2004-09-10 20:48:21 +0000137
Josh Bailey3f045a02012-03-24 08:35:20 -0700138 for (ALL_LIST_ELEMENTS_RO (lsp->area->circuit_list, cnode, circuit))
139 {
140 if (circuit->lsp_queue == NULL)
141 continue;
142 for (ALL_LIST_ELEMENTS (circuit->lsp_queue, lnode, lnnode, lsp_in_list))
143 if (lsp_in_list == lsp)
144 list_delete_node(circuit->lsp_queue, lnode);
145 }
146 ISIS_FLAGS_CLEAR_ALL (lsp->SSNflags);
147 ISIS_FLAGS_CLEAR_ALL (lsp->SRMflags);
148
jardineb5d44e2003-12-23 08:09:43 +0000149 lsp_clear_data (lsp);
hassof390d2c2004-09-10 20:48:21 +0000150
151 if (LSP_FRAGMENT (lsp->lsp_header->lsp_id) == 0 && lsp->lspu.frags)
152 {
jardineb5d44e2003-12-23 08:09:43 +0000153 list_delete (lsp->lspu.frags);
Josh Bailey3f045a02012-03-24 08:35:20 -0700154 lsp->lspu.frags = NULL;
hassof390d2c2004-09-10 20:48:21 +0000155 }
156
Josh Bailey3f045a02012-03-24 08:35:20 -0700157 isis_spf_schedule (lsp->area, lsp->level);
158#ifdef HAVE_IPV6
159 isis_spf_schedule6 (lsp->area, lsp->level);
160#endif
161
jardineb5d44e2003-12-23 08:09:43 +0000162 if (lsp->pdu)
163 stream_free (lsp->pdu);
164 XFREE (MTYPE_ISIS_LSP, lsp);
165}
166
hassof390d2c2004-09-10 20:48:21 +0000167void
168lsp_db_destroy (dict_t * lspdb)
jardineb5d44e2003-12-23 08:09:43 +0000169{
170 dnode_t *dnode, *next;
171 struct isis_lsp *lsp;
hassof390d2c2004-09-10 20:48:21 +0000172
jardineb5d44e2003-12-23 08:09:43 +0000173 dnode = dict_first (lspdb);
hassof390d2c2004-09-10 20:48:21 +0000174 while (dnode)
175 {
176 next = dict_next (lspdb, dnode);
177 lsp = dnode_get (dnode);
178 lsp_destroy (lsp);
179 dict_delete_free (lspdb, dnode);
180 dnode = next;
181 }
182
jardineb5d44e2003-12-23 08:09:43 +0000183 dict_free (lspdb);
hassof390d2c2004-09-10 20:48:21 +0000184
jardineb5d44e2003-12-23 08:09:43 +0000185 return;
186}
187
188/*
189 * Remove all the frags belonging to the given lsp
190 */
hasso92365882005-01-18 13:53:33 +0000191static void
hassof390d2c2004-09-10 20:48:21 +0000192lsp_remove_frags (struct list *frags, dict_t * lspdb)
jardineb5d44e2003-12-23 08:09:43 +0000193{
194 dnode_t *dnode;
paul1eb8ef22005-04-07 07:30:20 +0000195 struct listnode *lnode, *lnnode;
jardineb5d44e2003-12-23 08:09:43 +0000196 struct isis_lsp *lsp;
197
paul1eb8ef22005-04-07 07:30:20 +0000198 for (ALL_LIST_ELEMENTS (frags, lnode, lnnode, lsp))
hassof390d2c2004-09-10 20:48:21 +0000199 {
hassof390d2c2004-09-10 20:48:21 +0000200 dnode = dict_lookup (lspdb, lsp->lsp_header->lsp_id);
201 lsp_destroy (lsp);
202 dnode_destroy (dict_delete (lspdb, dnode));
203 }
204
jardineb5d44e2003-12-23 08:09:43 +0000205 list_delete_all_node (frags);
hassof390d2c2004-09-10 20:48:21 +0000206
jardineb5d44e2003-12-23 08:09:43 +0000207 return;
208}
209
210void
hassof390d2c2004-09-10 20:48:21 +0000211lsp_search_and_destroy (u_char * id, dict_t * lspdb)
jardineb5d44e2003-12-23 08:09:43 +0000212{
213 dnode_t *node;
214 struct isis_lsp *lsp;
215
216 node = dict_lookup (lspdb, id);
hassof390d2c2004-09-10 20:48:21 +0000217 if (node)
218 {
219 node = dict_delete (lspdb, node);
220 lsp = dnode_get (node);
221 /*
222 * If this is a zero lsp, remove all the frags now
223 */
224 if (LSP_FRAGMENT (lsp->lsp_header->lsp_id) == 0)
225 {
226 if (lsp->lspu.frags)
227 lsp_remove_frags (lsp->lspu.frags, lspdb);
228 }
229 else
230 {
231 /*
232 * else just remove this frag, from the zero lsps' frag list
233 */
234 if (lsp->lspu.zero_lsp && lsp->lspu.zero_lsp->lspu.frags)
235 listnode_delete (lsp->lspu.zero_lsp->lspu.frags, lsp);
236 }
237 lsp_destroy (lsp);
238 dnode_destroy (node);
jardineb5d44e2003-12-23 08:09:43 +0000239 }
jardineb5d44e2003-12-23 08:09:43 +0000240}
241
242/*
243 * Compares a LSP to given values
244 * Params are given in net order
245 */
hassof390d2c2004-09-10 20:48:21 +0000246int
247lsp_compare (char *areatag, struct isis_lsp *lsp, u_int32_t seq_num,
jardineb5d44e2003-12-23 08:09:43 +0000248 u_int16_t checksum, u_int16_t rem_lifetime)
249{
hassof390d2c2004-09-10 20:48:21 +0000250 /* no point in double ntohl on seqnum */
251 if (lsp->lsp_header->seq_num == seq_num &&
jardineb5d44e2003-12-23 08:09:43 +0000252 lsp->lsp_header->checksum == checksum &&
253 /*comparing with 0, no need to do ntohl */
254 ((lsp->lsp_header->rem_lifetime == 0 && rem_lifetime == 0) ||
hassof390d2c2004-09-10 20:48:21 +0000255 (lsp->lsp_header->rem_lifetime != 0 && rem_lifetime != 0)))
256 {
257 if (isis->debugs & DEBUG_SNP_PACKETS)
258 {
Josh Bailey3f045a02012-03-24 08:35:20 -0700259 zlog_debug ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x,"
hasso529d65b2004-12-24 00:14:50 +0000260 " lifetime %us",
261 areatag,
262 rawlspid_print (lsp->lsp_header->lsp_id),
263 ntohl (lsp->lsp_header->seq_num),
264 ntohs (lsp->lsp_header->checksum),
265 ntohs (lsp->lsp_header->rem_lifetime));
266 zlog_debug ("ISIS-Snp (%s): is equal to ours seq 0x%08x,"
267 " cksum 0x%04x, lifetime %us",
268 areatag,
269 ntohl (seq_num), ntohs (checksum), ntohs (rem_lifetime));
hassof390d2c2004-09-10 20:48:21 +0000270 }
271 return LSP_EQUAL;
jardineb5d44e2003-12-23 08:09:43 +0000272 }
jardineb5d44e2003-12-23 08:09:43 +0000273
hassof390d2c2004-09-10 20:48:21 +0000274 if (ntohl (seq_num) >= ntohl (lsp->lsp_header->seq_num))
275 {
276 if (isis->debugs & DEBUG_SNP_PACKETS)
277 {
Josh Bailey3f045a02012-03-24 08:35:20 -0700278 zlog_debug ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x,"
hasso529d65b2004-12-24 00:14:50 +0000279 " lifetime %us",
280 areatag,
281 rawlspid_print (lsp->lsp_header->lsp_id),
282 ntohl (seq_num), ntohs (checksum), ntohs (rem_lifetime));
283 zlog_debug ("ISIS-Snp (%s): is newer than ours seq 0x%08x, "
284 "cksum 0x%04x, lifetime %us",
285 areatag,
286 ntohl (lsp->lsp_header->seq_num),
287 ntohs (lsp->lsp_header->checksum),
288 ntohs (lsp->lsp_header->rem_lifetime));
hassof390d2c2004-09-10 20:48:21 +0000289 }
290 return LSP_NEWER;
jardineb5d44e2003-12-23 08:09:43 +0000291 }
hassof390d2c2004-09-10 20:48:21 +0000292 if (isis->debugs & DEBUG_SNP_PACKETS)
293 {
hasso529d65b2004-12-24 00:14:50 +0000294 zlog_debug
Josh Bailey3f045a02012-03-24 08:35:20 -0700295 ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x, lifetime %us",
hassof390d2c2004-09-10 20:48:21 +0000296 areatag, rawlspid_print (lsp->lsp_header->lsp_id), ntohl (seq_num),
297 ntohs (checksum), ntohs (rem_lifetime));
hasso529d65b2004-12-24 00:14:50 +0000298 zlog_debug ("ISIS-Snp (%s): is older than ours seq 0x%08x,"
299 " cksum 0x%04x, lifetime %us", areatag,
300 ntohl (lsp->lsp_header->seq_num),
301 ntohs (lsp->lsp_header->checksum),
302 ntohs (lsp->lsp_header->rem_lifetime));
hassof390d2c2004-09-10 20:48:21 +0000303 }
jardineb5d44e2003-12-23 08:09:43 +0000304
305 return LSP_OLDER;
306}
307
Josh Bailey3f045a02012-03-24 08:35:20 -0700308static void
309lsp_auth_add (struct isis_lsp *lsp)
310{
311 struct isis_passwd *passwd;
312 unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
313
314 /*
315 * Add the authentication info if its present
316 */
317 (lsp->level == IS_LEVEL_1) ? (passwd = &lsp->area->area_passwd) :
318 (passwd = &lsp->area->domain_passwd);
319 switch (passwd->type)
320 {
321 /* Cleartext */
322 case ISIS_PASSWD_TYPE_CLEARTXT:
323 memcpy (&lsp->tlv_data.auth_info, passwd, sizeof (struct isis_passwd));
324 tlv_add_authinfo (passwd->type, passwd->len, passwd->passwd, lsp->pdu);
325 break;
326
327 /* HMAC MD5 */
328 case ISIS_PASSWD_TYPE_HMAC_MD5:
329 /* Remember where TLV is written so we can later
330 * overwrite the MD5 hash */
331 lsp->auth_tlv_offset = stream_get_endp (lsp->pdu);
332 memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
333 lsp->tlv_data.auth_info.type = ISIS_PASSWD_TYPE_HMAC_MD5;
334 lsp->tlv_data.auth_info.len = ISIS_AUTH_MD5_SIZE;
335 memcpy (&lsp->tlv_data.auth_info.passwd, hmac_md5_hash,
336 ISIS_AUTH_MD5_SIZE);
337 tlv_add_authinfo (passwd->type, ISIS_AUTH_MD5_SIZE, hmac_md5_hash,
338 lsp->pdu);
339 break;
340
341 default:
342 break;
343 }
344}
345
346static void
347lsp_auth_update (struct isis_lsp *lsp)
348{
349 struct isis_passwd *passwd;
350 unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
351 uint16_t checksum, rem_lifetime;
352
353 /* For HMAC MD5 we need to recompute the md5 hash and store it */
354 (lsp->level == IS_LEVEL_1) ? (passwd = &lsp->area->area_passwd) :
355 (passwd = &lsp->area->domain_passwd);
356 if (passwd->type != ISIS_PASSWD_TYPE_HMAC_MD5)
357 return;
358
359 /*
360 * In transient conditions (when net is configured where authentication
361 * config and lsp regenerate schedule is not yet run), there could be
362 * an own_lsp with auth_tlv_offset set to 0. In such a case, simply
363 * return, when lsp_regenerate is run, lsp will have auth tlv.
364 */
365 if (lsp->auth_tlv_offset == 0)
366 return;
367
368 /*
369 * RFC 5304 set auth value, checksum and remaining lifetime to zero
370 * before computation and reset to old values after computation.
371 */
372 checksum = lsp->lsp_header->checksum;
373 rem_lifetime = lsp->lsp_header->rem_lifetime;
374 lsp->lsp_header->checksum = 0;
375 lsp->lsp_header->rem_lifetime = 0;
376 /* Set the authentication value as well to zero */
377 memset (STREAM_DATA (lsp->pdu) + lsp->auth_tlv_offset + 3,
378 0, ISIS_AUTH_MD5_SIZE);
379 /* Compute autentication value */
380 hmac_md5 (STREAM_DATA (lsp->pdu), stream_get_endp(lsp->pdu),
381 (unsigned char *) &passwd->passwd, passwd->len,
382 (caddr_t) &hmac_md5_hash);
383 /* Copy the hash into the stream */
384 memcpy (STREAM_DATA (lsp->pdu) + lsp->auth_tlv_offset + 3,
385 hmac_md5_hash, ISIS_AUTH_MD5_SIZE);
386 memcpy (&lsp->tlv_data.auth_info.passwd, hmac_md5_hash,
387 ISIS_AUTH_MD5_SIZE);
388 /* Copy back the checksum and remaining lifetime */
389 lsp->lsp_header->checksum = checksum;
390 lsp->lsp_header->rem_lifetime = rem_lifetime;
391}
392
hassof390d2c2004-09-10 20:48:21 +0000393void
jardineb5d44e2003-12-23 08:09:43 +0000394lsp_inc_seqnum (struct isis_lsp *lsp, u_int32_t seq_num)
395{
396 u_int32_t newseq;
hassof390d2c2004-09-10 20:48:21 +0000397
jardineb5d44e2003-12-23 08:09:43 +0000398 if (seq_num == 0 || ntohl (lsp->lsp_header->seq_num) > seq_num)
399 newseq = ntohl (lsp->lsp_header->seq_num) + 1;
400 else
Josh Bailey3f045a02012-03-24 08:35:20 -0700401 newseq = seq_num + 1;
hassof390d2c2004-09-10 20:48:21 +0000402
jardineb5d44e2003-12-23 08:09:43 +0000403 lsp->lsp_header->seq_num = htonl (newseq);
Josh Bailey3f045a02012-03-24 08:35:20 -0700404
405 /* Recompute authentication and checksum information */
406 lsp_auth_update (lsp);
407 /* ISO 10589 - 7.3.11 Generation of the checksum
408 * The checksum shall be computed over all fields in the LSP which appear
409 * after the Remaining Lifetime field. This field (and those appearing
410 * before it) are excluded so that the LSP may be aged by systems without
411 * requiring recomputation.
412 */
413 fletcher_checksum(STREAM_DATA (lsp->pdu) + 12,
414 ntohs (lsp->lsp_header->pdu_len) - 12, 12);
415
416 isis_spf_schedule (lsp->area, lsp->level);
417#ifdef HAVE_IPV6
418 isis_spf_schedule6 (lsp->area, lsp->level);
419#endif
jardineb5d44e2003-12-23 08:09:43 +0000420
421 return;
422}
423
424/*
425 * Genetates checksum for LSP and its frags
426 */
hasso92365882005-01-18 13:53:33 +0000427static void
jardineb5d44e2003-12-23 08:09:43 +0000428lsp_seqnum_update (struct isis_lsp *lsp0)
429{
430 struct isis_lsp *lsp;
hasso3fdb2dd2005-09-28 18:45:54 +0000431 struct listnode *node;
hassof390d2c2004-09-10 20:48:21 +0000432
jardineb5d44e2003-12-23 08:09:43 +0000433 lsp_inc_seqnum (lsp0, 0);
434
435 if (!lsp0->lspu.frags)
436 return;
437
hasso3fdb2dd2005-09-28 18:45:54 +0000438 for (ALL_LIST_ELEMENTS_RO (lsp0->lspu.frags, node, lsp))
paul1eb8ef22005-04-07 07:30:20 +0000439 lsp_inc_seqnum (lsp, 0);
hassof390d2c2004-09-10 20:48:21 +0000440
jardineb5d44e2003-12-23 08:09:43 +0000441 return;
442}
443
hasso92365882005-01-18 13:53:33 +0000444static void
hassof390d2c2004-09-10 20:48:21 +0000445lsp_update_data (struct isis_lsp *lsp, struct stream *stream,
Josh Bailey3f045a02012-03-24 08:35:20 -0700446 struct isis_area *area, int level)
jardineb5d44e2003-12-23 08:09:43 +0000447{
hassof390d2c2004-09-10 20:48:21 +0000448 uint32_t expected = 0, found;
jardineb5d44e2003-12-23 08:09:43 +0000449 int retval;
hassof390d2c2004-09-10 20:48:21 +0000450
Josh Bailey3f045a02012-03-24 08:35:20 -0700451 /* free the old lsp data */
452 lsp_clear_data (lsp);
453
jardineb5d44e2003-12-23 08:09:43 +0000454 /* copying only the relevant part of our stream */
Josh Bailey3f045a02012-03-24 08:35:20 -0700455 if (lsp->pdu != NULL)
456 stream_free (lsp->pdu);
paul15935e92005-05-03 09:27:23 +0000457 lsp->pdu = stream_dup (stream);
Josh Bailey3f045a02012-03-24 08:35:20 -0700458
jardineb5d44e2003-12-23 08:09:43 +0000459 /* setting pointers to the correct place */
hassof390d2c2004-09-10 20:48:21 +0000460 lsp->isis_header = (struct isis_fixed_hdr *) (STREAM_DATA (lsp->pdu));
461 lsp->lsp_header = (struct isis_link_state_hdr *) (STREAM_DATA (lsp->pdu) +
462 ISIS_FIXED_HDR_LEN);
Josh Bailey3f045a02012-03-24 08:35:20 -0700463 lsp->area = area;
464 lsp->level = level;
jardineb5d44e2003-12-23 08:09:43 +0000465 lsp->age_out = ZERO_AGE_LIFETIME;
hassof390d2c2004-09-10 20:48:21 +0000466 lsp->installed = time (NULL);
jardineb5d44e2003-12-23 08:09:43 +0000467 /*
468 * Get LSP data i.e. TLVs
469 */
470 expected |= TLVFLAG_AUTH_INFO;
471 expected |= TLVFLAG_AREA_ADDRS;
472 expected |= TLVFLAG_IS_NEIGHS;
hassof390d2c2004-09-10 20:48:21 +0000473 if ((lsp->lsp_header->lsp_bits & 3) == 3) /* a level 2 LSP */
jardineb5d44e2003-12-23 08:09:43 +0000474 expected |= TLVFLAG_PARTITION_DESIG_LEVEL2_IS;
475 expected |= TLVFLAG_NLPID;
476 if (area->dynhostname)
477 expected |= TLVFLAG_DYN_HOSTNAME;
hassof390d2c2004-09-10 20:48:21 +0000478 if (area->newmetric)
479 {
480 expected |= TLVFLAG_TE_IS_NEIGHS;
481 expected |= TLVFLAG_TE_IPV4_REACHABILITY;
482 expected |= TLVFLAG_TE_ROUTER_ID;
483 }
jardineb5d44e2003-12-23 08:09:43 +0000484 expected |= TLVFLAG_IPV4_ADDR;
485 expected |= TLVFLAG_IPV4_INT_REACHABILITY;
486 expected |= TLVFLAG_IPV4_EXT_REACHABILITY;
487#ifdef HAVE_IPV6
488 expected |= TLVFLAG_IPV6_ADDR;
489 expected |= TLVFLAG_IPV6_REACHABILITY;
490#endif /* HAVE_IPV6 */
491
Josh Bailey3f045a02012-03-24 08:35:20 -0700492 retval = parse_tlvs (area->area_tag, STREAM_DATA (lsp->pdu) +
493 ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN,
494 ntohs (lsp->lsp_header->pdu_len) -
495 ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN,
496 &expected, &found, &lsp->tlv_data,
497 NULL);
498 if (retval != ISIS_OK)
hassof390d2c2004-09-10 20:48:21 +0000499 {
Josh Bailey3f045a02012-03-24 08:35:20 -0700500 zlog_warn ("Could not parse LSP");
501 return;
502 }
503
504 if ((found & TLVFLAG_DYN_HOSTNAME) && (area->dynhostname))
505 {
hassof390d2c2004-09-10 20:48:21 +0000506 isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname,
507 (lsp->lsp_header->lsp_bits & LSPBIT_IST) ==
508 IS_LEVEL_1_AND_2 ? IS_LEVEL_2 :
509 (lsp->lsp_header->lsp_bits & LSPBIT_IST));
510 }
jardineb5d44e2003-12-23 08:09:43 +0000511
Josh Bailey3f045a02012-03-24 08:35:20 -0700512 return;
jardineb5d44e2003-12-23 08:09:43 +0000513}
514
515void
Josh Bailey3f045a02012-03-24 08:35:20 -0700516lsp_update (struct isis_lsp *lsp, struct stream *stream,
517 struct isis_area *area, int level)
jardineb5d44e2003-12-23 08:09:43 +0000518{
hasso4eda93a2005-09-18 17:51:02 +0000519 dnode_t *dnode = NULL;
hassoa96d8d12005-09-16 14:44:23 +0000520
Josh Bailey3f045a02012-03-24 08:35:20 -0700521 /* Remove old LSP from database. This is required since the
522 * lsp_update_data will free the lsp->pdu (which has the key, lsp_id)
523 * and will update it with the new data in the stream. */
hasso4eda93a2005-09-18 17:51:02 +0000524 dnode = dict_lookup (area->lspdb[level - 1], lsp->lsp_header->lsp_id);
525 if (dnode)
526 dnode_destroy (dict_delete (area->lspdb[level - 1], dnode));
hassoa96d8d12005-09-16 14:44:23 +0000527
jardineb5d44e2003-12-23 08:09:43 +0000528 /* rebuild the lsp data */
Josh Bailey3f045a02012-03-24 08:35:20 -0700529 lsp_update_data (lsp, stream, area, level);
jardineb5d44e2003-12-23 08:09:43 +0000530
Josh Bailey3f045a02012-03-24 08:35:20 -0700531 /* insert the lsp back into the database */
532 lsp_insert (lsp, area->lspdb[level - 1]);
jardineb5d44e2003-12-23 08:09:43 +0000533}
534
jardineb5d44e2003-12-23 08:09:43 +0000535/* creation of LSP directly from what we received */
536struct isis_lsp *
hassof390d2c2004-09-10 20:48:21 +0000537lsp_new_from_stream_ptr (struct stream *stream,
538 u_int16_t pdu_len, struct isis_lsp *lsp0,
Josh Bailey3f045a02012-03-24 08:35:20 -0700539 struct isis_area *area, int level)
jardineb5d44e2003-12-23 08:09:43 +0000540{
541 struct isis_lsp *lsp;
542
hassoaac372f2005-09-01 17:52:33 +0000543 lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp));
Josh Bailey3f045a02012-03-24 08:35:20 -0700544 lsp_update_data (lsp, stream, area, level);
hassof390d2c2004-09-10 20:48:21 +0000545
546 if (lsp0 == NULL)
547 {
548 /*
549 * zero lsp -> create the list for fragments
550 */
551 lsp->lspu.frags = list_new ();
552 }
553 else
554 {
555 /*
556 * a fragment -> set the backpointer and add this to zero lsps frag list
557 */
558 lsp->lspu.zero_lsp = lsp0;
559 listnode_add (lsp0->lspu.frags, lsp);
560 }
561
jardineb5d44e2003-12-23 08:09:43 +0000562 return lsp;
563}
564
565struct isis_lsp *
hassof390d2c2004-09-10 20:48:21 +0000566lsp_new (u_char * lsp_id, u_int16_t rem_lifetime, u_int32_t seq_num,
567 u_int8_t lsp_bits, u_int16_t checksum, int level)
jardineb5d44e2003-12-23 08:09:43 +0000568{
569 struct isis_lsp *lsp;
570
hassoaac372f2005-09-01 17:52:33 +0000571 lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp));
hassof390d2c2004-09-10 20:48:21 +0000572 if (!lsp)
573 {
574 /* FIXME: set lspdbol bit */
575 zlog_warn ("lsp_new(): out of memory");
576 return NULL;
577 }
Josh Bailey3f045a02012-03-24 08:35:20 -0700578 /* FIXME: Should be minimal mtu? */
579 lsp->pdu = stream_new (1500);
jardineb5d44e2003-12-23 08:09:43 +0000580 if (LSP_FRAGMENT (lsp_id) == 0)
581 lsp->lspu.frags = list_new ();
hassof390d2c2004-09-10 20:48:21 +0000582 lsp->isis_header = (struct isis_fixed_hdr *) (STREAM_DATA (lsp->pdu));
583 lsp->lsp_header = (struct isis_link_state_hdr *)
584 (STREAM_DATA (lsp->pdu) + ISIS_FIXED_HDR_LEN);
585
jardineb5d44e2003-12-23 08:09:43 +0000586 /* at first we fill the FIXED HEADER */
Josh Bailey3f045a02012-03-24 08:35:20 -0700587 (level == IS_LEVEL_1) ? fill_fixed_hdr (lsp->isis_header, L1_LINK_STATE) :
hassof390d2c2004-09-10 20:48:21 +0000588 fill_fixed_hdr (lsp->isis_header, L2_LINK_STATE);
589
jardineb5d44e2003-12-23 08:09:43 +0000590 /* now for the LSP HEADER */
591 /* Minimal LSP PDU size */
hassof390d2c2004-09-10 20:48:21 +0000592 lsp->lsp_header->pdu_len = htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
jardineb5d44e2003-12-23 08:09:43 +0000593 memcpy (lsp->lsp_header->lsp_id, lsp_id, ISIS_SYS_ID_LEN + 2);
hassof390d2c2004-09-10 20:48:21 +0000594 lsp->lsp_header->checksum = checksum; /* Provided in network order */
jardineb5d44e2003-12-23 08:09:43 +0000595 lsp->lsp_header->seq_num = htonl (seq_num);
596 lsp->lsp_header->rem_lifetime = htons (rem_lifetime);
597 lsp->lsp_header->lsp_bits = lsp_bits;
598 lsp->level = level;
599 lsp->age_out = ZERO_AGE_LIFETIME;
600
paul9985f832005-02-09 15:51:56 +0000601 stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
jardineb5d44e2003-12-23 08:09:43 +0000602
hassoc89c05d2005-09-04 21:36:36 +0000603 if (isis->debugs & DEBUG_EVENTS)
Josh Bailey3f045a02012-03-24 08:35:20 -0700604 zlog_debug ("New LSP with ID %s-%02x-%02x len %d seqnum %08x",
hassoc89c05d2005-09-04 21:36:36 +0000605 sysid_print (lsp_id), LSP_PSEUDO_ID (lsp->lsp_header->lsp_id),
606 LSP_FRAGMENT (lsp->lsp_header->lsp_id),
Josh Bailey3f045a02012-03-24 08:35:20 -0700607 ntohl (lsp->lsp_header->pdu_len),
hassoc89c05d2005-09-04 21:36:36 +0000608 ntohl (lsp->lsp_header->seq_num));
jardineb5d44e2003-12-23 08:09:43 +0000609
610 return lsp;
611}
612
613void
hassof390d2c2004-09-10 20:48:21 +0000614lsp_insert (struct isis_lsp *lsp, dict_t * lspdb)
jardineb5d44e2003-12-23 08:09:43 +0000615{
616 dict_alloc_insert (lspdb, lsp->lsp_header->lsp_id, lsp);
Josh Bailey3f045a02012-03-24 08:35:20 -0700617 if (lsp->lsp_header->seq_num != 0)
618 {
619 isis_spf_schedule (lsp->area, lsp->level);
620#ifdef HAVE_IPV6
621 isis_spf_schedule6 (lsp->area, lsp->level);
622#endif
623 }
jardineb5d44e2003-12-23 08:09:43 +0000624}
625
626/*
627 * Build a list of LSPs with non-zero ht bounded by start and stop ids
628 */
hassof390d2c2004-09-10 20:48:21 +0000629void
630lsp_build_list_nonzero_ht (u_char * start_id, u_char * stop_id,
631 struct list *list, dict_t * lspdb)
jardineb5d44e2003-12-23 08:09:43 +0000632{
633 dnode_t *first, *last, *curr;
634
635 first = dict_lower_bound (lspdb, start_id);
636 if (!first)
637 return;
hassof390d2c2004-09-10 20:48:21 +0000638
jardineb5d44e2003-12-23 08:09:43 +0000639 last = dict_upper_bound (lspdb, stop_id);
hassof390d2c2004-09-10 20:48:21 +0000640
jardineb5d44e2003-12-23 08:09:43 +0000641 curr = first;
hassof390d2c2004-09-10 20:48:21 +0000642
643 if (((struct isis_lsp *) (curr->dict_data))->lsp_header->rem_lifetime)
jardineb5d44e2003-12-23 08:09:43 +0000644 listnode_add (list, first->dict_data);
645
hassof390d2c2004-09-10 20:48:21 +0000646 while (curr)
647 {
648 curr = dict_next (lspdb, curr);
649 if (curr &&
650 ((struct isis_lsp *) (curr->dict_data))->lsp_header->rem_lifetime)
651 listnode_add (list, curr->dict_data);
652 if (curr == last)
653 break;
654 }
655
jardineb5d44e2003-12-23 08:09:43 +0000656 return;
657}
658
659/*
Josh Bailey3f045a02012-03-24 08:35:20 -0700660 * Build a list of num_lsps LSPs bounded by start_id and stop_id.
jardineb5d44e2003-12-23 08:09:43 +0000661 */
hassof390d2c2004-09-10 20:48:21 +0000662void
Josh Bailey3f045a02012-03-24 08:35:20 -0700663lsp_build_list (u_char * start_id, u_char * stop_id, u_char num_lsps,
hassof390d2c2004-09-10 20:48:21 +0000664 struct list *list, dict_t * lspdb)
jardineb5d44e2003-12-23 08:09:43 +0000665{
Josh Bailey3f045a02012-03-24 08:35:20 -0700666 u_char count;
jardineb5d44e2003-12-23 08:09:43 +0000667 dnode_t *first, *last, *curr;
668
669 first = dict_lower_bound (lspdb, start_id);
670 if (!first)
671 return;
hassof390d2c2004-09-10 20:48:21 +0000672
jardineb5d44e2003-12-23 08:09:43 +0000673 last = dict_upper_bound (lspdb, stop_id);
hassof390d2c2004-09-10 20:48:21 +0000674
jardineb5d44e2003-12-23 08:09:43 +0000675 curr = first;
hassof390d2c2004-09-10 20:48:21 +0000676
jardineb5d44e2003-12-23 08:09:43 +0000677 listnode_add (list, first->dict_data);
Josh Bailey3f045a02012-03-24 08:35:20 -0700678 count = 1;
jardineb5d44e2003-12-23 08:09:43 +0000679
hassof390d2c2004-09-10 20:48:21 +0000680 while (curr)
681 {
682 curr = dict_next (lspdb, curr);
683 if (curr)
Josh Bailey3f045a02012-03-24 08:35:20 -0700684 {
685 listnode_add (list, curr->dict_data);
686 count++;
687 }
688 if (count == num_lsps || curr == last)
689 break;
hassof390d2c2004-09-10 20:48:21 +0000690 }
691
jardineb5d44e2003-12-23 08:09:43 +0000692 return;
693}
694
695/*
696 * Build a list of LSPs with SSN flag set for the given circuit
697 */
698void
Josh Bailey3f045a02012-03-24 08:35:20 -0700699lsp_build_list_ssn (struct isis_circuit *circuit, u_char num_lsps,
700 struct list *list, dict_t * lspdb)
jardineb5d44e2003-12-23 08:09:43 +0000701{
702 dnode_t *dnode, *next;
703 struct isis_lsp *lsp;
Josh Bailey3f045a02012-03-24 08:35:20 -0700704 u_char count = 0;
hassof390d2c2004-09-10 20:48:21 +0000705
jardineb5d44e2003-12-23 08:09:43 +0000706 dnode = dict_first (lspdb);
hassof390d2c2004-09-10 20:48:21 +0000707 while (dnode != NULL)
708 {
709 next = dict_next (lspdb, dnode);
710 lsp = dnode_get (dnode);
711 if (ISIS_CHECK_FLAG (lsp->SSNflags, circuit))
Josh Bailey3f045a02012-03-24 08:35:20 -0700712 {
713 listnode_add (list, lsp);
714 ++count;
715 }
716 if (count == num_lsps)
717 break;
hassof390d2c2004-09-10 20:48:21 +0000718 dnode = next;
719 }
720
jardineb5d44e2003-12-23 08:09:43 +0000721 return;
722}
723
hasso92365882005-01-18 13:53:33 +0000724static void
jardineb5d44e2003-12-23 08:09:43 +0000725lsp_set_time (struct isis_lsp *lsp)
726{
727 assert (lsp);
hassof390d2c2004-09-10 20:48:21 +0000728
729 if (lsp->lsp_header->rem_lifetime == 0)
730 {
Josh Bailey3f045a02012-03-24 08:35:20 -0700731 if (lsp->age_out > 0)
732 lsp->age_out--;
hassof390d2c2004-09-10 20:48:21 +0000733 return;
734 }
jardineb5d44e2003-12-23 08:09:43 +0000735
hassof390d2c2004-09-10 20:48:21 +0000736 lsp->lsp_header->rem_lifetime =
jardineb5d44e2003-12-23 08:09:43 +0000737 htons (ntohs (lsp->lsp_header->rem_lifetime) - 1);
738}
739
hasso92365882005-01-18 13:53:33 +0000740static void
hassof390d2c2004-09-10 20:48:21 +0000741lspid_print (u_char * lsp_id, u_char * trg, char dynhost, char frag)
jardineb5d44e2003-12-23 08:09:43 +0000742{
743 struct isis_dynhn *dyn = NULL;
hassof390d2c2004-09-10 20:48:21 +0000744 u_char id[SYSID_STRLEN];
jardineb5d44e2003-12-23 08:09:43 +0000745
746 if (dynhost)
747 dyn = dynhn_find_by_id (lsp_id);
748 else
749 dyn = NULL;
750
751 if (dyn)
Josh Bailey3f045a02012-03-24 08:35:20 -0700752 sprintf ((char *)id, "%.14s", dyn->name.name);
753 else if (!memcmp (isis->sysid, lsp_id, ISIS_SYS_ID_LEN) && dynhost)
754 sprintf ((char *)id, "%.14s", unix_hostname ());
jardineb5d44e2003-12-23 08:09:43 +0000755 else
hassof390d2c2004-09-10 20:48:21 +0000756 memcpy (id, sysid_print (lsp_id), 15);
hassof390d2c2004-09-10 20:48:21 +0000757 if (frag)
hassof7c43dc2004-09-26 16:24:14 +0000758 sprintf ((char *)trg, "%s.%02x-%02x", id, LSP_PSEUDO_ID (lsp_id),
hassof390d2c2004-09-10 20:48:21 +0000759 LSP_FRAGMENT (lsp_id));
760 else
hassof7c43dc2004-09-26 16:24:14 +0000761 sprintf ((char *)trg, "%s.%02x", id, LSP_PSEUDO_ID (lsp_id));
jardineb5d44e2003-12-23 08:09:43 +0000762}
763
hassof390d2c2004-09-10 20:48:21 +0000764/* Convert the lsp attribute bits to attribute string */
hasso1cd80842004-10-07 20:07:40 +0000765const char *
hassof390d2c2004-09-10 20:48:21 +0000766lsp_bits2string (u_char * lsp_bits)
767{
768 char *pos = lsp_bits_string;
jardineb5d44e2003-12-23 08:09:43 +0000769
hassof390d2c2004-09-10 20:48:21 +0000770 if (!*lsp_bits)
jardineb5d44e2003-12-23 08:09:43 +0000771 return " none";
772
773 /* we only focus on the default metric */
774 pos += sprintf (pos, "%d/",
hassof390d2c2004-09-10 20:48:21 +0000775 ISIS_MASK_LSP_ATT_DEFAULT_BIT (*lsp_bits) ? 1 : 0);
jardineb5d44e2003-12-23 08:09:43 +0000776
777 pos += sprintf (pos, "%d/",
hassof390d2c2004-09-10 20:48:21 +0000778 ISIS_MASK_LSP_PARTITION_BIT (*lsp_bits) ? 1 : 0);
jardineb5d44e2003-12-23 08:09:43 +0000779
hassof390d2c2004-09-10 20:48:21 +0000780 pos += sprintf (pos, "%d", ISIS_MASK_LSP_OL_BIT (*lsp_bits) ? 1 : 0);
781
jardineb5d44e2003-12-23 08:09:43 +0000782 *(pos) = '\0';
jardineb5d44e2003-12-23 08:09:43 +0000783
hassof390d2c2004-09-10 20:48:21 +0000784 return lsp_bits_string;
jardineb5d44e2003-12-23 08:09:43 +0000785}
786
787/* this function prints the lsp on show isis database */
Josh Bailey3f045a02012-03-24 08:35:20 -0700788void
789lsp_print (struct isis_lsp *lsp, struct vty *vty, char dynhost)
jardineb5d44e2003-12-23 08:09:43 +0000790{
jardineb5d44e2003-12-23 08:09:43 +0000791 u_char LSPid[255];
Josh Bailey3f045a02012-03-24 08:35:20 -0700792 char age_out[8];
jardineb5d44e2003-12-23 08:09:43 +0000793
794 lspid_print (lsp->lsp_header->lsp_id, LSPid, dynhost, 1);
Josh Bailey3f045a02012-03-24 08:35:20 -0700795 vty_out (vty, "%-21s%c ", LSPid, lsp->own_lsp ? '*' : ' ');
796 vty_out (vty, "%5u ", ntohs (lsp->lsp_header->pdu_len));
797 vty_out (vty, "0x%08x ", ntohl (lsp->lsp_header->seq_num));
798 vty_out (vty, "0x%04x ", ntohs (lsp->lsp_header->checksum));
hassof390d2c2004-09-10 20:48:21 +0000799 if (ntohs (lsp->lsp_header->rem_lifetime) == 0)
Josh Bailey3f045a02012-03-24 08:35:20 -0700800 {
801 snprintf (age_out, 8, "(%u)", lsp->age_out);
802 age_out[7] = '\0';
803 vty_out (vty, "%7s ", age_out);
804 }
jardineb5d44e2003-12-23 08:09:43 +0000805 else
Josh Bailey3f045a02012-03-24 08:35:20 -0700806 vty_out (vty, " %5u ", ntohs (lsp->lsp_header->rem_lifetime));
807 vty_out (vty, "%s%s",
808 lsp_bits2string (&lsp->lsp_header->lsp_bits), VTY_NEWLINE);
jardineb5d44e2003-12-23 08:09:43 +0000809}
810
Josh Bailey3f045a02012-03-24 08:35:20 -0700811void
812lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost)
jardineb5d44e2003-12-23 08:09:43 +0000813{
jardineb5d44e2003-12-23 08:09:43 +0000814 struct area_addr *area_addr;
hassof390d2c2004-09-10 20:48:21 +0000815 int i;
hasso3fdb2dd2005-09-28 18:45:54 +0000816 struct listnode *lnode;
jardineb5d44e2003-12-23 08:09:43 +0000817 struct is_neigh *is_neigh;
818 struct te_is_neigh *te_is_neigh;
819 struct ipv4_reachability *ipv4_reach;
820 struct in_addr *ipv4_addr;
821 struct te_ipv4_reachability *te_ipv4_reach;
822#ifdef HAVE_IPV6
823 struct ipv6_reachability *ipv6_reach;
824 struct in6_addr in6;
Paul Jakma41b36e92006-12-08 01:09:50 +0000825 u_char buff[BUFSIZ];
jardineb5d44e2003-12-23 08:09:43 +0000826#endif
827 u_char LSPid[255];
828 u_char hostname[255];
jardineb5d44e2003-12-23 08:09:43 +0000829 u_char ipv4_reach_prefix[20];
830 u_char ipv4_reach_mask[20];
831 u_char ipv4_address[20];
832
833 lspid_print (lsp->lsp_header->lsp_id, LSPid, dynhost, 1);
Josh Bailey3f045a02012-03-24 08:35:20 -0700834 lsp_print (lsp, vty, dynhost);
jardineb5d44e2003-12-23 08:09:43 +0000835
836 /* for all area address */
hassof390d2c2004-09-10 20:48:21 +0000837 if (lsp->tlv_data.area_addrs)
hasso3fdb2dd2005-09-28 18:45:54 +0000838 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.area_addrs, lnode, area_addr))
hassof390d2c2004-09-10 20:48:21 +0000839 {
hasso1cd80842004-10-07 20:07:40 +0000840 vty_out (vty, " Area Address: %s%s",
hassof390d2c2004-09-10 20:48:21 +0000841 isonet_print (area_addr->area_addr, area_addr->addr_len),
842 VTY_NEWLINE);
843 }
paul1eb8ef22005-04-07 07:30:20 +0000844
jardineb5d44e2003-12-23 08:09:43 +0000845 /* for the nlpid tlv */
hassof390d2c2004-09-10 20:48:21 +0000846 if (lsp->tlv_data.nlpids)
847 {
848 for (i = 0; i < lsp->tlv_data.nlpids->count; i++)
849 {
850 switch (lsp->tlv_data.nlpids->nlpids[i])
851 {
852 case NLPID_IP:
853 case NLPID_IPV6:
Josh Bailey3f045a02012-03-24 08:35:20 -0700854 vty_out (vty, " NLPID : 0x%X%s",
hassof390d2c2004-09-10 20:48:21 +0000855 lsp->tlv_data.nlpids->nlpids[i], VTY_NEWLINE);
856 break;
857 default:
Josh Bailey3f045a02012-03-24 08:35:20 -0700858 vty_out (vty, " NLPID : %s%s", "unknown", VTY_NEWLINE);
hassof390d2c2004-09-10 20:48:21 +0000859 break;
860 }
861 }
862 }
jardineb5d44e2003-12-23 08:09:43 +0000863
864 /* for the hostname tlv */
hassof390d2c2004-09-10 20:48:21 +0000865 if (lsp->tlv_data.hostname)
866 {
Josh Bailey3f045a02012-03-24 08:35:20 -0700867 bzero (hostname, sizeof (hostname));
hassof390d2c2004-09-10 20:48:21 +0000868 memcpy (hostname, lsp->tlv_data.hostname->name,
869 lsp->tlv_data.hostname->namelen);
Josh Bailey3f045a02012-03-24 08:35:20 -0700870 vty_out (vty, " Hostname : %s%s", hostname, VTY_NEWLINE);
jardineb5d44e2003-12-23 08:09:43 +0000871 }
hassof390d2c2004-09-10 20:48:21 +0000872
Josh Bailey3f045a02012-03-24 08:35:20 -0700873 /* authentication tlv */
874 if (lsp->tlv_data.auth_info.type != ISIS_PASSWD_TYPE_UNUSED)
875 {
876 if (lsp->tlv_data.auth_info.type == ISIS_PASSWD_TYPE_HMAC_MD5)
877 vty_out (vty, " Auth type : md5%s", VTY_NEWLINE);
878 else if (lsp->tlv_data.auth_info.type == ISIS_PASSWD_TYPE_CLEARTXT)
879 vty_out (vty, " Auth type : clear text%s", VTY_NEWLINE);
880 }
hassof390d2c2004-09-10 20:48:21 +0000881
hasso1cd80842004-10-07 20:07:40 +0000882 /* TE router id */
883 if (lsp->tlv_data.router_id)
884 {
885 memcpy (ipv4_address, inet_ntoa (lsp->tlv_data.router_id->id),
886 sizeof (ipv4_address));
Josh Bailey3f045a02012-03-24 08:35:20 -0700887 vty_out (vty, " Router ID : %s%s", ipv4_address, VTY_NEWLINE);
hasso1cd80842004-10-07 20:07:40 +0000888 }
889
Josh Bailey3f045a02012-03-24 08:35:20 -0700890 if (lsp->tlv_data.ipv4_addrs)
891 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_addrs, lnode, ipv4_addr))
892 {
893 memcpy (ipv4_address, inet_ntoa (*ipv4_addr), sizeof (ipv4_address));
894 vty_out (vty, " IPv4 Address: %s%s", ipv4_address, VTY_NEWLINE);
895 }
896
hasso1cd80842004-10-07 20:07:40 +0000897 /* for the IS neighbor tlv */
898 if (lsp->tlv_data.is_neighs)
hasso3fdb2dd2005-09-28 18:45:54 +0000899 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, lnode, is_neigh))
hasso1cd80842004-10-07 20:07:40 +0000900 {
901 lspid_print (is_neigh->neigh_id, LSPid, dynhost, 0);
Josh Bailey3f045a02012-03-24 08:35:20 -0700902 vty_out (vty, " Metric : %-8d IS : %s%s",
hasso1cd80842004-10-07 20:07:40 +0000903 is_neigh->metrics.metric_default, LSPid, VTY_NEWLINE);
904 }
hasso1cd80842004-10-07 20:07:40 +0000905
jardineb5d44e2003-12-23 08:09:43 +0000906 /* for the internal reachable tlv */
907 if (lsp->tlv_data.ipv4_int_reachs)
hasso3fdb2dd2005-09-28 18:45:54 +0000908 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_int_reachs, lnode,
909 ipv4_reach))
hassof390d2c2004-09-10 20:48:21 +0000910 {
911 memcpy (ipv4_reach_prefix, inet_ntoa (ipv4_reach->prefix),
912 sizeof (ipv4_reach_prefix));
913 memcpy (ipv4_reach_mask, inet_ntoa (ipv4_reach->mask),
914 sizeof (ipv4_reach_mask));
Josh Bailey3f045a02012-03-24 08:35:20 -0700915 vty_out (vty, " Metric : %-8d IPv4-Internal : %s %s%s",
hassof390d2c2004-09-10 20:48:21 +0000916 ipv4_reach->metrics.metric_default, ipv4_reach_prefix,
917 ipv4_reach_mask, VTY_NEWLINE);
918 }
hasso2097cd82003-12-23 11:51:08 +0000919
920 /* for the external reachable tlv */
921 if (lsp->tlv_data.ipv4_ext_reachs)
hasso3fdb2dd2005-09-28 18:45:54 +0000922 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_ext_reachs, lnode,
923 ipv4_reach))
hassof390d2c2004-09-10 20:48:21 +0000924 {
925 memcpy (ipv4_reach_prefix, inet_ntoa (ipv4_reach->prefix),
926 sizeof (ipv4_reach_prefix));
927 memcpy (ipv4_reach_mask, inet_ntoa (ipv4_reach->mask),
928 sizeof (ipv4_reach_mask));
Josh Bailey3f045a02012-03-24 08:35:20 -0700929 vty_out (vty, " Metric : %-8d IPv4-External : %s %s%s",
hassof390d2c2004-09-10 20:48:21 +0000930 ipv4_reach->metrics.metric_default, ipv4_reach_prefix,
931 ipv4_reach_mask, VTY_NEWLINE);
932 }
paul1eb8ef22005-04-07 07:30:20 +0000933
hasso2097cd82003-12-23 11:51:08 +0000934 /* IPv6 tlv */
935#ifdef HAVE_IPV6
936 if (lsp->tlv_data.ipv6_reachs)
hasso3fdb2dd2005-09-28 18:45:54 +0000937 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv6_reachs, lnode, ipv6_reach))
hassof390d2c2004-09-10 20:48:21 +0000938 {
939 memset (&in6, 0, sizeof (in6));
940 memcpy (in6.s6_addr, ipv6_reach->prefix,
941 PSIZE (ipv6_reach->prefix_len));
hassof7c43dc2004-09-26 16:24:14 +0000942 inet_ntop (AF_INET6, &in6, (char *)buff, BUFSIZ);
hasso2097cd82003-12-23 11:51:08 +0000943 if ((ipv6_reach->control_info &&
hassof390d2c2004-09-10 20:48:21 +0000944 CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL)
Josh Bailey3f045a02012-03-24 08:35:20 -0700945 vty_out (vty, " Metric : %-8d IPv6-Internal : %s/%d%s",
hassof390d2c2004-09-10 20:48:21 +0000946 ntohl (ipv6_reach->metric),
947 buff, ipv6_reach->prefix_len, VTY_NEWLINE);
hasso2097cd82003-12-23 11:51:08 +0000948 else
Josh Bailey3f045a02012-03-24 08:35:20 -0700949 vty_out (vty, " Metric : %-8d IPv6-External : %s/%d%s",
hassof390d2c2004-09-10 20:48:21 +0000950 ntohl (ipv6_reach->metric),
951 buff, ipv6_reach->prefix_len, VTY_NEWLINE);
hasso2097cd82003-12-23 11:51:08 +0000952 }
953#endif
paul1eb8ef22005-04-07 07:30:20 +0000954
hasso1cd80842004-10-07 20:07:40 +0000955 /* TE IS neighbor tlv */
jardineb5d44e2003-12-23 08:09:43 +0000956 if (lsp->tlv_data.te_is_neighs)
hasso3fdb2dd2005-09-28 18:45:54 +0000957 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, lnode, te_is_neigh))
hassof390d2c2004-09-10 20:48:21 +0000958 {
hassof390d2c2004-09-10 20:48:21 +0000959 lspid_print (te_is_neigh->neigh_id, LSPid, dynhost, 0);
Josh Bailey3f045a02012-03-24 08:35:20 -0700960 vty_out (vty, " Metric : %-8d IS-Extended : %s%s",
961 GET_TE_METRIC(te_is_neigh), LSPid, VTY_NEWLINE);
hassof390d2c2004-09-10 20:48:21 +0000962 }
jardineb5d44e2003-12-23 08:09:43 +0000963
hasso1cd80842004-10-07 20:07:40 +0000964 /* TE IPv4 tlv */
jardineb5d44e2003-12-23 08:09:43 +0000965 if (lsp->tlv_data.te_ipv4_reachs)
hasso3fdb2dd2005-09-28 18:45:54 +0000966 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_ipv4_reachs, lnode,
967 te_ipv4_reach))
hassof390d2c2004-09-10 20:48:21 +0000968 {
hasso1cd80842004-10-07 20:07:40 +0000969 /* FIXME: There should be better way to output this stuff. */
Josh Bailey3f045a02012-03-24 08:35:20 -0700970 vty_out (vty, " Metric : %-8d IPv4-Extended : %s/%d%s",
hasso1cd80842004-10-07 20:07:40 +0000971 ntohl (te_ipv4_reach->te_metric),
hassof390d2c2004-09-10 20:48:21 +0000972 inet_ntoa (newprefix2inaddr (&te_ipv4_reach->prefix_start,
973 te_ipv4_reach->control)),
hasso1cd80842004-10-07 20:07:40 +0000974 te_ipv4_reach->control & 0x3F, VTY_NEWLINE);
hassof390d2c2004-09-10 20:48:21 +0000975 }
Josh Bailey3f045a02012-03-24 08:35:20 -0700976 vty_out (vty, "%s", VTY_NEWLINE);
jardineb5d44e2003-12-23 08:09:43 +0000977
hassof390d2c2004-09-10 20:48:21 +0000978 return;
jardineb5d44e2003-12-23 08:09:43 +0000979}
980
981/* print all the lsps info in the local lspdb */
hassof390d2c2004-09-10 20:48:21 +0000982int
983lsp_print_all (struct vty *vty, dict_t * lspdb, char detail, char dynhost)
jardineb5d44e2003-12-23 08:09:43 +0000984{
985
hassof390d2c2004-09-10 20:48:21 +0000986 dnode_t *node = dict_first (lspdb), *next;
jardineb5d44e2003-12-23 08:09:43 +0000987 int lsp_count = 0;
988
hassof390d2c2004-09-10 20:48:21 +0000989 if (detail == ISIS_UI_LEVEL_BRIEF)
990 {
991 while (node != NULL)
992 {
993 /* I think it is unnecessary, so I comment it out */
994 /* dict_contains (lspdb, node); */
995 next = dict_next (lspdb, node);
Josh Bailey3f045a02012-03-24 08:35:20 -0700996 lsp_print (dnode_get (node), vty, dynhost);
hassof390d2c2004-09-10 20:48:21 +0000997 node = next;
998 lsp_count++;
999 }
jardineb5d44e2003-12-23 08:09:43 +00001000 }
hassof390d2c2004-09-10 20:48:21 +00001001 else if (detail == ISIS_UI_LEVEL_DETAIL)
1002 {
1003 while (node != NULL)
1004 {
1005 next = dict_next (lspdb, node);
Josh Bailey3f045a02012-03-24 08:35:20 -07001006 lsp_print_detail (dnode_get (node), vty, dynhost);
hassof390d2c2004-09-10 20:48:21 +00001007 node = next;
1008 lsp_count++;
1009 }
jardineb5d44e2003-12-23 08:09:43 +00001010 }
jardineb5d44e2003-12-23 08:09:43 +00001011
1012 return lsp_count;
1013}
1014
jardineb5d44e2003-12-23 08:09:43 +00001015#define FRAG_THOLD(S,T) \
Josh Bailey3f045a02012-03-24 08:35:20 -07001016 ((STREAM_SIZE(S)*T)/100)
jardineb5d44e2003-12-23 08:09:43 +00001017
1018/* stream*, area->lsp_frag_threshold, increment */
1019#define FRAG_NEEDED(S,T,I) \
1020 (STREAM_SIZE(S)-STREAM_REMAIN(S)+(I) > FRAG_THOLD(S,T))
1021
hassoaa4376e2005-09-26 17:39:48 +00001022/* FIXME: It shouldn't be necessary to pass tlvsize here, TLVs can have
1023 * variable length (TE TLVs, sub TLVs). */
hasso92365882005-01-18 13:53:33 +00001024static void
jardineb5d44e2003-12-23 08:09:43 +00001025lsp_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to,
hassof390d2c2004-09-10 20:48:21 +00001026 int tlvsize, int frag_thold,
1027 int tlv_build_func (struct list *, struct stream *))
jardineb5d44e2003-12-23 08:09:43 +00001028{
1029 int count, i;
hassof390d2c2004-09-10 20:48:21 +00001030
jardineb5d44e2003-12-23 08:09:43 +00001031 /* can we fit all ? */
hassof390d2c2004-09-10 20:48:21 +00001032 if (!FRAG_NEEDED (lsp->pdu, frag_thold, listcount (*from) * tlvsize + 2))
1033 {
1034 tlv_build_func (*from, lsp->pdu);
Josh Bailey3f045a02012-03-24 08:35:20 -07001035 if (listcount (*to) != 0)
1036 {
1037 struct listnode *node, *nextnode;
1038 void *elem;
1039
1040 for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem))
1041 {
1042 listnode_add (*to, elem);
1043 list_delete_node (*from, node);
1044 }
1045 }
1046 else
1047 {
1048 list_free (*to);
1049 *to = *from;
1050 *from = NULL;
1051 }
jardineb5d44e2003-12-23 08:09:43 +00001052 }
hassof390d2c2004-09-10 20:48:21 +00001053 else if (!FRAG_NEEDED (lsp->pdu, frag_thold, tlvsize + 2))
1054 {
1055 /* fit all we can */
1056 count = FRAG_THOLD (lsp->pdu, frag_thold) - 2 -
1057 (STREAM_SIZE (lsp->pdu) - STREAM_REMAIN (lsp->pdu));
Josh Bailey3f045a02012-03-24 08:35:20 -07001058 count = count / tlvsize;
1059 if (count > (int)listcount (*from))
1060 count = listcount (*from);
hassof390d2c2004-09-10 20:48:21 +00001061 for (i = 0; i < count; i++)
1062 {
paul1eb8ef22005-04-07 07:30:20 +00001063 listnode_add (*to, listgetdata (listhead (*from)));
1064 listnode_delete (*from, listgetdata (listhead (*from)));
hassof390d2c2004-09-10 20:48:21 +00001065 }
1066 tlv_build_func (*to, lsp->pdu);
1067 }
paul9985f832005-02-09 15:51:56 +00001068 lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
jardineb5d44e2003-12-23 08:09:43 +00001069 return;
1070}
1071
Josh Bailey3f045a02012-03-24 08:35:20 -07001072static u_int16_t
1073lsp_rem_lifetime (struct isis_area *area, int level)
1074{
1075 u_int16_t rem_lifetime;
1076
1077 /* Add jitter to configured LSP lifetime */
1078 rem_lifetime = isis_jitter (area->max_lsp_lifetime[level - 1],
1079 MAX_AGE_JITTER);
1080
1081 /* No jitter if the max refresh will be less than configure gen interval */
1082 if (area->lsp_gen_interval[level - 1] > (rem_lifetime - 300))
1083 rem_lifetime = area->max_lsp_lifetime[level - 1];
1084
1085 return rem_lifetime;
1086}
1087
1088static u_int16_t
1089lsp_refresh_time (struct isis_lsp *lsp, u_int16_t rem_lifetime)
1090{
1091 struct isis_area *area = lsp->area;
1092 int level = lsp->level;
1093 u_int16_t refresh_time;
1094
1095 /* Add jitter to LSP refresh time */
1096 refresh_time = isis_jitter (area->lsp_refresh[level - 1],
1097 MAX_LSP_GEN_JITTER);
1098
1099 /* RFC 4444 : make sure the refresh time is at least less than 300
1100 * of the remaining lifetime and more than gen interval */
1101 if (refresh_time <= area->lsp_gen_interval[level - 1] ||
1102 refresh_time > (rem_lifetime - 300))
1103 refresh_time = rem_lifetime - 300;
1104
1105 assert (area->lsp_gen_interval[level - 1] < refresh_time);
1106
1107 return refresh_time;
1108}
1109
hasso92365882005-01-18 13:53:33 +00001110static struct isis_lsp *
hassof390d2c2004-09-10 20:48:21 +00001111lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0, struct isis_area *area,
1112 int level)
jardineb5d44e2003-12-23 08:09:43 +00001113{
1114 struct isis_lsp *lsp;
hassof390d2c2004-09-10 20:48:21 +00001115 u_char frag_id[ISIS_SYS_ID_LEN + 2];
1116
jardineb5d44e2003-12-23 08:09:43 +00001117 memcpy (frag_id, lsp0->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 1);
1118 LSP_FRAGMENT (frag_id) = frag_num;
Josh Bailey3f045a02012-03-24 08:35:20 -07001119 /* FIXME add authentication TLV for fragment LSPs */
jardineb5d44e2003-12-23 08:09:43 +00001120 lsp = lsp_search (frag_id, area->lspdb[level - 1]);
hassof390d2c2004-09-10 20:48:21 +00001121 if (lsp)
1122 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001123 /* Clear the TLVs */
hassof390d2c2004-09-10 20:48:21 +00001124 lsp_clear_data (lsp);
hassof390d2c2004-09-10 20:48:21 +00001125 return lsp;
jardineb5d44e2003-12-23 08:09:43 +00001126 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001127 lsp = lsp_new (frag_id, ntohs(lsp0->lsp_header->rem_lifetime), 0,
1128 area->is_type | area->overload_bit, 0, level);
1129 lsp->area = area;
jardineb5d44e2003-12-23 08:09:43 +00001130 lsp->own_lsp = 1;
hassof390d2c2004-09-10 20:48:21 +00001131 lsp_insert (lsp, area->lspdb[level - 1]);
jardineb5d44e2003-12-23 08:09:43 +00001132 listnode_add (lsp0->lspu.frags, lsp);
1133 lsp->lspu.zero_lsp = lsp0;
jardineb5d44e2003-12-23 08:09:43 +00001134 return lsp;
1135}
1136
1137/*
1138 * Builds the LSP data part. This func creates a new frag whenever
1139 * area->lsp_frag_threshold is exceeded.
1140 */
hasso92365882005-01-18 13:53:33 +00001141static void
Josh Bailey3f045a02012-03-24 08:35:20 -07001142lsp_build (struct isis_lsp *lsp, struct isis_area *area)
jardineb5d44e2003-12-23 08:09:43 +00001143{
1144 struct is_neigh *is_neigh;
hassoaa4376e2005-09-26 17:39:48 +00001145 struct te_is_neigh *te_is_neigh;
hasso3fdb2dd2005-09-28 18:45:54 +00001146 struct listnode *node, *ipnode;
jardineb5d44e2003-12-23 08:09:43 +00001147 int level = lsp->level;
1148 struct isis_circuit *circuit;
1149 struct prefix_ipv4 *ipv4;
1150 struct ipv4_reachability *ipreach;
hassoaa4376e2005-09-26 17:39:48 +00001151 struct te_ipv4_reachability *te_ipreach;
jardineb5d44e2003-12-23 08:09:43 +00001152 struct isis_adjacency *nei;
1153#ifdef HAVE_IPV6
hasso67851572004-09-21 14:17:04 +00001154 struct prefix_ipv6 *ipv6, *ip6prefix;
jardineb5d44e2003-12-23 08:09:43 +00001155 struct ipv6_reachability *ip6reach;
1156#endif /* HAVE_IPV6 */
1157 struct tlvs tlv_data;
1158 struct isis_lsp *lsp0 = lsp;
hasso18a6dce2004-10-03 18:18:34 +00001159 struct in_addr *routerid;
Josh Bailey3f045a02012-03-24 08:35:20 -07001160 uint32_t expected = 0, found = 0;
1161 uint32_t metric;
1162 u_char zero_id[ISIS_SYS_ID_LEN + 1];
1163 int retval = ISIS_OK;
1164
1165 /*
1166 * Building the zero lsp
1167 */
1168 memset (zero_id, 0, ISIS_SYS_ID_LEN + 1);
1169
1170 /* Reset stream endp. Stream is always there and on every LSP refresh only
1171 * TLV part of it is overwritten. So we must seek past header we will not
1172 * touch. */
1173 stream_reset (lsp->pdu);
1174 stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
1175
1176 /*
1177 * Add the authentication info if its present
1178 */
1179 lsp_auth_add (lsp);
jardineb5d44e2003-12-23 08:09:43 +00001180
1181 /*
1182 * First add the tlvs related to area
1183 */
hassof390d2c2004-09-10 20:48:21 +00001184
jardineb5d44e2003-12-23 08:09:43 +00001185 /* Area addresses */
1186 if (lsp->tlv_data.area_addrs == NULL)
1187 lsp->tlv_data.area_addrs = list_new ();
1188 list_add_list (lsp->tlv_data.area_addrs, area->area_addrs);
Josh Bailey3f045a02012-03-24 08:35:20 -07001189 if (listcount (lsp->tlv_data.area_addrs) > 0)
1190 tlv_add_area_addrs (lsp->tlv_data.area_addrs, lsp->pdu);
1191
jardineb5d44e2003-12-23 08:09:43 +00001192 /* Protocols Supported */
hassof390d2c2004-09-10 20:48:21 +00001193 if (area->ip_circuits > 0
jardineb5d44e2003-12-23 08:09:43 +00001194#ifdef HAVE_IPV6
1195 || area->ipv6_circuits > 0
1196#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +00001197 )
jardineb5d44e2003-12-23 08:09:43 +00001198 {
hassoaac372f2005-09-01 17:52:33 +00001199 lsp->tlv_data.nlpids = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct nlpids));
jardineb5d44e2003-12-23 08:09:43 +00001200 lsp->tlv_data.nlpids->count = 0;
hassof390d2c2004-09-10 20:48:21 +00001201 if (area->ip_circuits > 0)
1202 {
1203 lsp->tlv_data.nlpids->count++;
1204 lsp->tlv_data.nlpids->nlpids[0] = NLPID_IP;
1205 }
jardineb5d44e2003-12-23 08:09:43 +00001206#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +00001207 if (area->ipv6_circuits > 0)
1208 {
1209 lsp->tlv_data.nlpids->count++;
1210 lsp->tlv_data.nlpids->nlpids[lsp->tlv_data.nlpids->count - 1] =
1211 NLPID_IPV6;
1212 }
jardineb5d44e2003-12-23 08:09:43 +00001213#endif /* HAVE_IPV6 */
Josh Bailey3f045a02012-03-24 08:35:20 -07001214 tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu);
jardineb5d44e2003-12-23 08:09:43 +00001215 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001216
jardineb5d44e2003-12-23 08:09:43 +00001217 /* Dynamic Hostname */
hassof390d2c2004-09-10 20:48:21 +00001218 if (area->dynhostname)
1219 {
1220 lsp->tlv_data.hostname = XMALLOC (MTYPE_ISIS_TLV,
1221 sizeof (struct hostname));
jardin9e867fe2003-12-23 08:56:18 +00001222
hassof390d2c2004-09-10 20:48:21 +00001223 memcpy (lsp->tlv_data.hostname->name, unix_hostname (),
1224 strlen (unix_hostname ()));
1225 lsp->tlv_data.hostname->namelen = strlen (unix_hostname ());
Josh Bailey3f045a02012-03-24 08:35:20 -07001226 tlv_add_dynamic_hostname (lsp->tlv_data.hostname, lsp->pdu);
hassof390d2c2004-09-10 20:48:21 +00001227 }
jardineb5d44e2003-12-23 08:09:43 +00001228
hasso81ad8f62005-09-26 17:58:24 +00001229 /* IPv4 address and TE router ID TLVs. In case of the first one we don't
1230 * follow "C" vendor, but "J" vendor behavior - one IPv4 address is put into
1231 * LSP and this address is same as router id. */
Josh Bailey3f045a02012-03-24 08:35:20 -07001232 if (isis->router_id != 0)
hasso18a6dce2004-10-03 18:18:34 +00001233 {
hasso18a6dce2004-10-03 18:18:34 +00001234 if (lsp->tlv_data.ipv4_addrs == NULL)
hassobe7d65d2005-09-02 01:38:16 +00001235 {
1236 lsp->tlv_data.ipv4_addrs = list_new ();
1237 lsp->tlv_data.ipv4_addrs->del = free_tlv;
1238 }
hasso18a6dce2004-10-03 18:18:34 +00001239
1240 routerid = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct in_addr));
Josh Bailey3f045a02012-03-24 08:35:20 -07001241 routerid->s_addr = isis->router_id;
hasso18a6dce2004-10-03 18:18:34 +00001242 listnode_add (lsp->tlv_data.ipv4_addrs, routerid);
hasso81ad8f62005-09-26 17:58:24 +00001243 tlv_add_in_addr (routerid, lsp->pdu, IPV4_ADDR);
hasso18a6dce2004-10-03 18:18:34 +00001244
hasso81ad8f62005-09-26 17:58:24 +00001245 /* Exactly same data is put into TE router ID TLV, but only if new style
1246 * TLV's are in use. */
1247 if (area->newmetric)
1248 {
1249 lsp->tlv_data.router_id = XMALLOC (MTYPE_ISIS_TLV,
1250 sizeof (struct in_addr));
Josh Bailey3f045a02012-03-24 08:35:20 -07001251 lsp->tlv_data.router_id->id.s_addr = isis->router_id;
1252 tlv_add_in_addr (&lsp->tlv_data.router_id->id, lsp->pdu,
1253 TE_ROUTER_ID);
hasso81ad8f62005-09-26 17:58:24 +00001254 }
hasso18a6dce2004-10-03 18:18:34 +00001255 }
hassof1082d12005-09-19 04:23:34 +00001256
hasso81ad8f62005-09-26 17:58:24 +00001257 memset (&tlv_data, 0, sizeof (struct tlvs));
1258
hassof1082d12005-09-19 04:23:34 +00001259#ifdef TOPOLOGY_GENERATE
1260 /* If topology exists (and we create topology for level 1 only), create
1261 * (hardcoded) link to topology. */
Josh Bailey3f045a02012-03-24 08:35:20 -07001262 if (area->topology && level == IS_LEVEL_1)
hassof1082d12005-09-19 04:23:34 +00001263 {
1264 if (tlv_data.is_neighs == NULL)
hassoaa4376e2005-09-26 17:39:48 +00001265 {
1266 tlv_data.is_neighs = list_new ();
1267 tlv_data.is_neighs->del = free_tlv;
1268 }
hasso3fdb2dd2005-09-28 18:45:54 +00001269 is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
hassof1082d12005-09-19 04:23:34 +00001270
1271 memcpy (&is_neigh->neigh_id, area->topology_baseis, ISIS_SYS_ID_LEN);
1272 is_neigh->neigh_id[ISIS_SYS_ID_LEN - 1] = (1 & 0xFF);
1273 is_neigh->neigh_id[ISIS_SYS_ID_LEN - 2] = ((1 >> 8) & 0xFF);
1274 is_neigh->metrics.metric_default = 0x01;
1275 is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED;
1276 is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED;
1277 is_neigh->metrics.metric_error = METRICS_UNSUPPORTED;
1278 listnode_add (tlv_data.is_neighs, is_neigh);
1279 }
1280#endif /* TOPOLOGY_GENERATE */
1281
hasso18a6dce2004-10-03 18:18:34 +00001282 /*
jardineb5d44e2003-12-23 08:09:43 +00001283 * Then build lists of tlvs related to circuits
1284 */
hasso3fdb2dd2005-09-28 18:45:54 +00001285 for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit))
hassof390d2c2004-09-10 20:48:21 +00001286 {
hassof390d2c2004-09-10 20:48:21 +00001287 if (circuit->state != C_STATE_UP)
1288 continue;
jardineb5d44e2003-12-23 08:09:43 +00001289
hassof390d2c2004-09-10 20:48:21 +00001290 /*
1291 * Add IPv4 internal reachability of this circuit
1292 */
1293 if (circuit->ip_router && circuit->ip_addrs &&
1294 circuit->ip_addrs->count > 0)
1295 {
hassoaa4376e2005-09-26 17:39:48 +00001296 if (area->oldmetric)
hassof390d2c2004-09-10 20:48:21 +00001297 {
hassoaa4376e2005-09-26 17:39:48 +00001298 if (tlv_data.ipv4_int_reachs == NULL)
1299 {
1300 tlv_data.ipv4_int_reachs = list_new ();
1301 tlv_data.ipv4_int_reachs->del = free_tlv;
1302 }
hasso3fdb2dd2005-09-28 18:45:54 +00001303 for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, ipnode, ipv4))
hassoaa4376e2005-09-26 17:39:48 +00001304 {
1305 ipreach =
1306 XMALLOC (MTYPE_ISIS_TLV, sizeof (struct ipv4_reachability));
1307 ipreach->metrics = circuit->metrics[level - 1];
1308 masklen2ip (ipv4->prefixlen, &ipreach->mask);
1309 ipreach->prefix.s_addr = ((ipreach->mask.s_addr) &
1310 (ipv4->prefix.s_addr));
1311 listnode_add (tlv_data.ipv4_int_reachs, ipreach);
1312 }
hassof390d2c2004-09-10 20:48:21 +00001313 }
hassoaa4376e2005-09-26 17:39:48 +00001314 if (area->newmetric)
hassof390d2c2004-09-10 20:48:21 +00001315 {
hassoaa4376e2005-09-26 17:39:48 +00001316 if (tlv_data.te_ipv4_reachs == NULL)
1317 {
1318 tlv_data.te_ipv4_reachs = list_new ();
1319 tlv_data.te_ipv4_reachs->del = free_tlv;
1320 }
hasso3fdb2dd2005-09-28 18:45:54 +00001321 for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, ipnode, ipv4))
hassoaa4376e2005-09-26 17:39:48 +00001322 {
1323 /* FIXME All this assumes that we have no sub TLVs. */
1324 te_ipreach = XCALLOC (MTYPE_ISIS_TLV,
1325 sizeof (struct te_ipv4_reachability) +
1326 ((ipv4->prefixlen + 7)/8) - 1);
hasso309ddb12005-09-26 18:06:47 +00001327
1328 if (area->oldmetric)
1329 te_ipreach->te_metric = htonl (circuit->metrics[level - 1].metric_default);
1330 else
1331 te_ipreach->te_metric = htonl (circuit->te_metric[level - 1]);
1332
hassoaa4376e2005-09-26 17:39:48 +00001333 te_ipreach->control = (ipv4->prefixlen & 0x3F);
1334 memcpy (&te_ipreach->prefix_start, &ipv4->prefix.s_addr,
1335 (ipv4->prefixlen + 7)/8);
1336 listnode_add (tlv_data.te_ipv4_reachs, te_ipreach);
1337 }
hassof390d2c2004-09-10 20:48:21 +00001338 }
hassof390d2c2004-09-10 20:48:21 +00001339 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001340
jardineb5d44e2003-12-23 08:09:43 +00001341#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +00001342 /*
1343 * Add IPv6 reachability of this circuit
1344 */
1345 if (circuit->ipv6_router && circuit->ipv6_non_link &&
1346 circuit->ipv6_non_link->count > 0)
1347 {
1348
1349 if (tlv_data.ipv6_reachs == NULL)
1350 {
1351 tlv_data.ipv6_reachs = list_new ();
hassobe7d65d2005-09-02 01:38:16 +00001352 tlv_data.ipv6_reachs->del = free_tlv;
hassof390d2c2004-09-10 20:48:21 +00001353 }
hasso3fdb2dd2005-09-28 18:45:54 +00001354 for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, ipnode, ipv6))
hassof390d2c2004-09-10 20:48:21 +00001355 {
hassof390d2c2004-09-10 20:48:21 +00001356 ip6reach =
hassoaac372f2005-09-01 17:52:33 +00001357 XCALLOC (MTYPE_ISIS_TLV, sizeof (struct ipv6_reachability));
hasso309ddb12005-09-26 18:06:47 +00001358
1359 if (area->oldmetric)
1360 ip6reach->metric =
1361 htonl (circuit->metrics[level - 1].metric_default);
1362 else
1363 ip6reach->metric = htonl (circuit->te_metric[level - 1]);
1364
hassof390d2c2004-09-10 20:48:21 +00001365 ip6reach->control_info = 0;
1366 ip6reach->prefix_len = ipv6->prefixlen;
hasso67851572004-09-21 14:17:04 +00001367 memcpy (&ip6prefix, &ipv6, sizeof(ip6prefix));
1368 apply_mask_ipv6 (ip6prefix);
1369 memcpy (ip6reach->prefix, ip6prefix->prefix.s6_addr,
1370 sizeof (ip6reach->prefix));
hassof390d2c2004-09-10 20:48:21 +00001371 listnode_add (tlv_data.ipv6_reachs, ip6reach);
1372 }
1373 }
1374#endif /* HAVE_IPV6 */
1375
1376 switch (circuit->circ_type)
1377 {
1378 case CIRCUIT_T_BROADCAST:
Josh Bailey3f045a02012-03-24 08:35:20 -07001379 if (level & circuit->is_type)
hassof390d2c2004-09-10 20:48:21 +00001380 {
hassoaa4376e2005-09-26 17:39:48 +00001381 if (area->oldmetric)
hassof390d2c2004-09-10 20:48:21 +00001382 {
hassoaa4376e2005-09-26 17:39:48 +00001383 if (tlv_data.is_neighs == NULL)
1384 {
1385 tlv_data.is_neighs = list_new ();
1386 tlv_data.is_neighs->del = free_tlv;
1387 }
1388 is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
Josh Bailey3f045a02012-03-24 08:35:20 -07001389 if (level == IS_LEVEL_1)
hassoaa4376e2005-09-26 17:39:48 +00001390 memcpy (is_neigh->neigh_id,
1391 circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
1392 else
1393 memcpy (is_neigh->neigh_id,
1394 circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
1395 is_neigh->metrics = circuit->metrics[level - 1];
Josh Bailey3f045a02012-03-24 08:35:20 -07001396 if (!memcmp (is_neigh->neigh_id, zero_id,
1397 ISIS_SYS_ID_LEN + 1))
1398 XFREE (MTYPE_ISIS_TLV, is_neigh);
1399 else
1400 listnode_add (tlv_data.is_neighs, is_neigh);
hassof390d2c2004-09-10 20:48:21 +00001401 }
hassoaa4376e2005-09-26 17:39:48 +00001402 if (area->newmetric)
1403 {
hassoaa4376e2005-09-26 17:39:48 +00001404 if (tlv_data.te_is_neighs == NULL)
1405 {
1406 tlv_data.te_is_neighs = list_new ();
1407 tlv_data.te_is_neighs->del = free_tlv;
1408 }
1409 te_is_neigh = XCALLOC (MTYPE_ISIS_TLV,
1410 sizeof (struct te_is_neigh));
Josh Bailey3f045a02012-03-24 08:35:20 -07001411 if (level == IS_LEVEL_1)
hassoaa4376e2005-09-26 17:39:48 +00001412 memcpy (te_is_neigh->neigh_id,
1413 circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
1414 else
1415 memcpy (te_is_neigh->neigh_id,
1416 circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
hasso309ddb12005-09-26 18:06:47 +00001417 if (area->oldmetric)
Josh Bailey3f045a02012-03-24 08:35:20 -07001418 metric = circuit->metrics[level - 1].metric_default;
hasso309ddb12005-09-26 18:06:47 +00001419 else
Josh Bailey3f045a02012-03-24 08:35:20 -07001420 metric = circuit->te_metric[level - 1];
1421 SET_TE_METRIC(te_is_neigh, metric);
1422 if (!memcmp (te_is_neigh->neigh_id, zero_id,
1423 ISIS_SYS_ID_LEN + 1))
1424 XFREE (MTYPE_ISIS_TLV, te_is_neigh);
1425 else
1426 listnode_add (tlv_data.te_is_neighs, te_is_neigh);
hassoaa4376e2005-09-26 17:39:48 +00001427 }
hassof390d2c2004-09-10 20:48:21 +00001428 }
1429 break;
1430 case CIRCUIT_T_P2P:
1431 nei = circuit->u.p2p.neighbor;
1432 if (nei && (level & nei->circuit_t))
1433 {
hassoaa4376e2005-09-26 17:39:48 +00001434 if (area->oldmetric)
hassof390d2c2004-09-10 20:48:21 +00001435 {
hassoaa4376e2005-09-26 17:39:48 +00001436 if (tlv_data.is_neighs == NULL)
1437 {
1438 tlv_data.is_neighs = list_new ();
1439 tlv_data.is_neighs->del = free_tlv;
1440 }
1441 is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
1442 memcpy (is_neigh->neigh_id, nei->sysid, ISIS_SYS_ID_LEN);
1443 is_neigh->metrics = circuit->metrics[level - 1];
1444 listnode_add (tlv_data.is_neighs, is_neigh);
hassof390d2c2004-09-10 20:48:21 +00001445 }
hassoaa4376e2005-09-26 17:39:48 +00001446 if (area->newmetric)
1447 {
1448 uint32_t metric;
1449
1450 if (tlv_data.te_is_neighs == NULL)
1451 {
1452 tlv_data.te_is_neighs = list_new ();
1453 tlv_data.te_is_neighs->del = free_tlv;
1454 }
1455 te_is_neigh = XCALLOC (MTYPE_ISIS_TLV,
1456 sizeof (struct te_is_neigh));
1457 memcpy (te_is_neigh->neigh_id, nei->sysid, ISIS_SYS_ID_LEN);
Josh Bailey3f045a02012-03-24 08:35:20 -07001458 metric = circuit->te_metric[level - 1];
1459 SET_TE_METRIC(te_is_neigh, metric);
hassoaa4376e2005-09-26 17:39:48 +00001460 listnode_add (tlv_data.te_is_neighs, te_is_neigh);
1461 }
hassof390d2c2004-09-10 20:48:21 +00001462 }
1463 break;
Josh Bailey3f045a02012-03-24 08:35:20 -07001464 case CIRCUIT_T_LOOPBACK:
1465 break;
hassof390d2c2004-09-10 20:48:21 +00001466 default:
1467 zlog_warn ("lsp_area_create: unknown circuit type");
1468 }
1469 }
1470
1471 while (tlv_data.ipv4_int_reachs && listcount (tlv_data.ipv4_int_reachs))
1472 {
1473 if (lsp->tlv_data.ipv4_int_reachs == NULL)
1474 lsp->tlv_data.ipv4_int_reachs = list_new ();
1475 lsp_tlv_fit (lsp, &tlv_data.ipv4_int_reachs,
1476 &lsp->tlv_data.ipv4_int_reachs,
1477 IPV4_REACH_LEN, area->lsp_frag_threshold,
1478 tlv_add_ipv4_reachs);
1479 if (tlv_data.ipv4_int_reachs && listcount (tlv_data.ipv4_int_reachs))
1480 lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
1481 lsp0, area, level);
1482 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001483
hassoaa4376e2005-09-26 17:39:48 +00001484 /* FIXME: We pass maximum te_ipv4_reachability length to the lsp_tlv_fit()
1485 * for now. lsp_tlv_fit() needs to be fixed to deal with variable length
1486 * TLVs (sub TLVs!). */
1487 while (tlv_data.te_ipv4_reachs && listcount (tlv_data.te_ipv4_reachs))
1488 {
1489 if (lsp->tlv_data.te_ipv4_reachs == NULL)
1490 lsp->tlv_data.te_ipv4_reachs = list_new ();
1491 lsp_tlv_fit (lsp, &tlv_data.te_ipv4_reachs,
1492 &lsp->tlv_data.te_ipv4_reachs,
Josh Bailey3f045a02012-03-24 08:35:20 -07001493 TE_IPV4_REACH_LEN, area->lsp_frag_threshold,
1494 tlv_add_te_ipv4_reachs);
hassoaa4376e2005-09-26 17:39:48 +00001495 if (tlv_data.te_ipv4_reachs && listcount (tlv_data.te_ipv4_reachs))
1496 lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
1497 lsp0, area, level);
1498 }
hassof390d2c2004-09-10 20:48:21 +00001499
1500#ifdef HAVE_IPV6
1501 while (tlv_data.ipv6_reachs && listcount (tlv_data.ipv6_reachs))
1502 {
1503 if (lsp->tlv_data.ipv6_reachs == NULL)
1504 lsp->tlv_data.ipv6_reachs = list_new ();
1505 lsp_tlv_fit (lsp, &tlv_data.ipv6_reachs,
1506 &lsp->tlv_data.ipv6_reachs,
1507 IPV6_REACH_LEN, area->lsp_frag_threshold,
1508 tlv_add_ipv6_reachs);
1509 if (tlv_data.ipv6_reachs && listcount (tlv_data.ipv6_reachs))
1510 lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
1511 lsp0, area, level);
jardineb5d44e2003-12-23 08:09:43 +00001512 }
1513#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +00001514
1515 while (tlv_data.is_neighs && listcount (tlv_data.is_neighs))
1516 {
1517 if (lsp->tlv_data.is_neighs == NULL)
1518 lsp->tlv_data.is_neighs = list_new ();
1519 lsp_tlv_fit (lsp, &tlv_data.is_neighs,
1520 &lsp->tlv_data.is_neighs,
1521 IS_NEIGHBOURS_LEN, area->lsp_frag_threshold,
1522 tlv_add_is_neighs);
1523 if (tlv_data.is_neighs && listcount (tlv_data.is_neighs))
1524 lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
1525 lsp0, area, level);
jardineb5d44e2003-12-23 08:09:43 +00001526 }
jardineb5d44e2003-12-23 08:09:43 +00001527
hassoaa4376e2005-09-26 17:39:48 +00001528 while (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs))
1529 {
1530 if (lsp->tlv_data.te_is_neighs == NULL)
1531 lsp->tlv_data.te_is_neighs = list_new ();
1532 lsp_tlv_fit (lsp, &tlv_data.te_is_neighs, &lsp->tlv_data.te_is_neighs,
1533 IS_NEIGHBOURS_LEN, area->lsp_frag_threshold,
1534 tlv_add_te_is_neighs);
1535 if (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs))
1536 lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
1537 lsp0, area, level);
1538 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001539 lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
hassoaa4376e2005-09-26 17:39:48 +00001540
1541 free_tlvs (&tlv_data);
Josh Bailey3f045a02012-03-24 08:35:20 -07001542
1543 /* Validate the LSP */
1544 retval = parse_tlvs (area->area_tag, STREAM_DATA (lsp->pdu) +
1545 ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN,
1546 stream_get_endp (lsp->pdu) -
1547 ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN,
1548 &expected, &found, &tlv_data, NULL);
1549 assert (retval == ISIS_OK);
1550
jardineb5d44e2003-12-23 08:09:43 +00001551 return;
1552}
jardineb5d44e2003-12-23 08:09:43 +00001553
1554/*
Josh Bailey3f045a02012-03-24 08:35:20 -07001555 * 7.3.7 and 7.3.9 Generation on non-pseudonode LSPs
jardineb5d44e2003-12-23 08:09:43 +00001556 */
Josh Bailey3f045a02012-03-24 08:35:20 -07001557int
1558lsp_generate (struct isis_area *area, int level)
hassof390d2c2004-09-10 20:48:21 +00001559{
jardineb5d44e2003-12-23 08:09:43 +00001560 struct isis_lsp *oldlsp, *newlsp;
1561 u_int32_t seq_num = 0;
1562 u_char lspid[ISIS_SYS_ID_LEN + 2];
Josh Bailey3f045a02012-03-24 08:35:20 -07001563 u_int16_t rem_lifetime, refresh_time;
1564
1565 if ((area == NULL) || (area->is_type & level) != level)
1566 return ISIS_ERROR;
jardineb5d44e2003-12-23 08:09:43 +00001567
1568 memset (&lspid, 0, ISIS_SYS_ID_LEN + 2);
1569 memcpy (&lspid, isis->sysid, ISIS_SYS_ID_LEN);
1570
1571 /* only builds the lsp if the area shares the level */
Josh Bailey3f045a02012-03-24 08:35:20 -07001572 oldlsp = lsp_search (lspid, area->lspdb[level - 1]);
1573 if (oldlsp)
hassof390d2c2004-09-10 20:48:21 +00001574 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001575 /* FIXME: we should actually initiate a purge */
1576 seq_num = ntohl (oldlsp->lsp_header->seq_num);
1577 lsp_search_and_destroy (oldlsp->lsp_header->lsp_id,
1578 area->lspdb[level - 1]);
hassof390d2c2004-09-10 20:48:21 +00001579 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001580 rem_lifetime = lsp_rem_lifetime (area, level);
1581 newlsp = lsp_new (lspid, rem_lifetime, seq_num,
1582 area->is_type | area->overload_bit, 0, level);
1583 newlsp->area = area;
1584 newlsp->own_lsp = 1;
jardineb5d44e2003-12-23 08:09:43 +00001585
Josh Bailey3f045a02012-03-24 08:35:20 -07001586 lsp_insert (newlsp, area->lspdb[level - 1]);
1587 /* build_lsp_data (newlsp, area); */
1588 lsp_build (newlsp, area);
1589 /* time to calculate our checksum */
1590 lsp_seqnum_update (newlsp);
1591 lsp_set_all_srmflags (newlsp);
1592
1593 refresh_time = lsp_refresh_time (newlsp, rem_lifetime);
1594 THREAD_TIMER_OFF (area->t_lsp_refresh[level - 1]);
1595 if (level == IS_LEVEL_1)
1596 THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
1597 lsp_l1_refresh, area, refresh_time);
1598 else if (level == IS_LEVEL_2)
1599 THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
1600 lsp_l2_refresh, area, refresh_time);
1601
1602 if (isis->debugs & DEBUG_UPDATE_PACKETS)
hassof390d2c2004-09-10 20:48:21 +00001603 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001604 zlog_debug ("ISIS-Upd (%s): Building L%d LSP %s, len %d, "
1605 "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us",
1606 area->area_tag, level,
1607 rawlspid_print (newlsp->lsp_header->lsp_id),
1608 ntohl (newlsp->lsp_header->pdu_len),
1609 ntohl (newlsp->lsp_header->seq_num),
1610 ntohs (newlsp->lsp_header->checksum),
1611 ntohs (newlsp->lsp_header->rem_lifetime),
1612 refresh_time);
hassof390d2c2004-09-10 20:48:21 +00001613 }
jardineb5d44e2003-12-23 08:09:43 +00001614
1615 return ISIS_OK;
1616}
1617
1618/*
Josh Bailey3f045a02012-03-24 08:35:20 -07001619 * Search own LSPs, update holding time and set SRM
jardineb5d44e2003-12-23 08:09:43 +00001620 */
hasso92365882005-01-18 13:53:33 +00001621static int
Josh Bailey3f045a02012-03-24 08:35:20 -07001622lsp_regenerate (struct isis_area *area, int level)
jardineb5d44e2003-12-23 08:09:43 +00001623{
1624 dict_t *lspdb = area->lspdb[level - 1];
1625 struct isis_lsp *lsp, *frag;
1626 struct listnode *node;
1627 u_char lspid[ISIS_SYS_ID_LEN + 2];
Josh Bailey3f045a02012-03-24 08:35:20 -07001628 u_int16_t rem_lifetime, refresh_time;
1629
1630 if ((area == NULL) || (area->is_type & level) != level)
1631 return ISIS_ERROR;
jardineb5d44e2003-12-23 08:09:43 +00001632
1633 memset (lspid, 0, ISIS_SYS_ID_LEN + 2);
1634 memcpy (lspid, isis->sysid, ISIS_SYS_ID_LEN);
hassof390d2c2004-09-10 20:48:21 +00001635
jardineb5d44e2003-12-23 08:09:43 +00001636 lsp = lsp_search (lspid, lspdb);
jardineb5d44e2003-12-23 08:09:43 +00001637
hassof390d2c2004-09-10 20:48:21 +00001638 if (!lsp)
1639 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001640 zlog_err ("ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!",
1641 area->area_tag, level);
hassof390d2c2004-09-10 20:48:21 +00001642 return ISIS_ERROR;
1643 }
1644
1645 lsp_clear_data (lsp);
Josh Bailey3f045a02012-03-24 08:35:20 -07001646 lsp_build (lsp, area);
1647 lsp->lsp_header->lsp_bits = area->is_type | area->overload_bit;
1648 rem_lifetime = lsp_rem_lifetime (area, level);
1649 lsp->lsp_header->rem_lifetime = htons (rem_lifetime);
jardineb5d44e2003-12-23 08:09:43 +00001650 lsp_seqnum_update (lsp);
hassof390d2c2004-09-10 20:48:21 +00001651
Josh Bailey3f045a02012-03-24 08:35:20 -07001652 lsp->last_generated = time (NULL);
1653 lsp_set_all_srmflags (lsp);
1654 for (ALL_LIST_ELEMENTS_RO (lsp->lspu.frags, node, frag))
1655 {
1656 frag->lsp_header->lsp_bits = area->is_type | area->overload_bit;
1657 /* Set the lifetime values of all the fragments to the same value,
1658 * so that no fragment expires before the lsp is refreshed.
1659 */
1660 frag->lsp_header->rem_lifetime = htons (rem_lifetime);
1661 lsp_set_all_srmflags (frag);
1662 }
1663
1664 refresh_time = lsp_refresh_time (lsp, rem_lifetime);
1665 if (level == IS_LEVEL_1)
1666 THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
1667 lsp_l1_refresh, area, refresh_time);
1668 else if (level == IS_LEVEL_2)
1669 THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
1670 lsp_l2_refresh, area, refresh_time);
1671
hassof390d2c2004-09-10 20:48:21 +00001672 if (isis->debugs & DEBUG_UPDATE_PACKETS)
1673 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001674 zlog_debug ("ISIS-Upd (%s): Refreshing our L%d LSP %s, len %d, "
1675 "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us",
1676 area->area_tag, level,
1677 rawlspid_print (lsp->lsp_header->lsp_id),
1678 ntohl (lsp->lsp_header->pdu_len),
1679 ntohl (lsp->lsp_header->seq_num),
1680 ntohs (lsp->lsp_header->checksum),
1681 ntohs (lsp->lsp_header->rem_lifetime),
1682 refresh_time);
hassof390d2c2004-09-10 20:48:21 +00001683 }
jardineb5d44e2003-12-23 08:09:43 +00001684
jardineb5d44e2003-12-23 08:09:43 +00001685 return ISIS_OK;
1686}
1687
jardineb5d44e2003-12-23 08:09:43 +00001688/*
Josh Bailey3f045a02012-03-24 08:35:20 -07001689 * Something has changed or periodic refresh -> regenerate LSP
jardineb5d44e2003-12-23 08:09:43 +00001690 */
Josh Bailey3f045a02012-03-24 08:35:20 -07001691static int
1692lsp_l1_refresh (struct thread *thread)
jardineb5d44e2003-12-23 08:09:43 +00001693{
1694 struct isis_area *area;
jardineb5d44e2003-12-23 08:09:43 +00001695
1696 area = THREAD_ARG (thread);
1697 assert (area);
hassof390d2c2004-09-10 20:48:21 +00001698
jardineb5d44e2003-12-23 08:09:43 +00001699 area->t_lsp_refresh[0] = NULL;
Josh Bailey3f045a02012-03-24 08:35:20 -07001700 area->lsp_regenerate_pending[0] = 0;
hassof390d2c2004-09-10 20:48:21 +00001701
Josh Bailey3f045a02012-03-24 08:35:20 -07001702 if ((area->is_type & IS_LEVEL_1) == 0)
1703 return ISIS_ERROR;
jardineb5d44e2003-12-23 08:09:43 +00001704
Josh Bailey3f045a02012-03-24 08:35:20 -07001705 return lsp_regenerate (area, IS_LEVEL_1);
jardineb5d44e2003-12-23 08:09:43 +00001706}
1707
Josh Bailey3f045a02012-03-24 08:35:20 -07001708static int
1709lsp_l2_refresh (struct thread *thread)
jardineb5d44e2003-12-23 08:09:43 +00001710{
1711 struct isis_area *area;
jardineb5d44e2003-12-23 08:09:43 +00001712
1713 area = THREAD_ARG (thread);
1714 assert (area);
hassof390d2c2004-09-10 20:48:21 +00001715
jardineb5d44e2003-12-23 08:09:43 +00001716 area->t_lsp_refresh[1] = NULL;
jardineb5d44e2003-12-23 08:09:43 +00001717 area->lsp_regenerate_pending[1] = 0;
hassof390d2c2004-09-10 20:48:21 +00001718
Josh Bailey3f045a02012-03-24 08:35:20 -07001719 if ((area->is_type & IS_LEVEL_2) == 0)
1720 return ISIS_ERROR;
1721
1722 return lsp_regenerate (area, IS_LEVEL_2);
jardineb5d44e2003-12-23 08:09:43 +00001723}
1724
hassof390d2c2004-09-10 20:48:21 +00001725int
Josh Bailey3f045a02012-03-24 08:35:20 -07001726lsp_regenerate_schedule (struct isis_area *area, int level, int all_pseudo)
jardineb5d44e2003-12-23 08:09:43 +00001727{
1728 struct isis_lsp *lsp;
1729 u_char id[ISIS_SYS_ID_LEN + 2];
1730 time_t now, diff;
Josh Bailey3f045a02012-03-24 08:35:20 -07001731 struct listnode *cnode;
1732 struct isis_circuit *circuit;
1733 int lvl;
1734
1735 if (area == NULL)
1736 return ISIS_ERROR;
1737
hassof390d2c2004-09-10 20:48:21 +00001738 memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
1739 LSP_PSEUDO_ID (id) = LSP_FRAGMENT (id) = 0;
jardineb5d44e2003-12-23 08:09:43 +00001740 now = time (NULL);
Josh Bailey3f045a02012-03-24 08:35:20 -07001741
1742 for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++)
hassof390d2c2004-09-10 20:48:21 +00001743 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001744 if (!((level & lvl) && (area->is_type & lvl)))
1745 continue;
1746
1747 if (area->lsp_regenerate_pending[lvl - 1])
1748 continue;
1749
1750 lsp = lsp_search (id, area->lspdb[lvl - 1]);
1751 if (!lsp)
1752 continue;
1753
hassof390d2c2004-09-10 20:48:21 +00001754 /*
1755 * Throttle avoidance
1756 */
Josh Bailey3f045a02012-03-24 08:35:20 -07001757 THREAD_TIMER_OFF (area->t_lsp_refresh[lvl - 1]);
hassof390d2c2004-09-10 20:48:21 +00001758 diff = now - lsp->last_generated;
Josh Bailey3f045a02012-03-24 08:35:20 -07001759 if (diff < area->lsp_gen_interval[lvl - 1])
1760 {
1761 area->lsp_regenerate_pending[lvl - 1] = 1;
1762 if (lvl == IS_LEVEL_1)
1763 THREAD_TIMER_ON (master, area->t_lsp_refresh[lvl - 1],
1764 lsp_l1_refresh, area,
1765 area->lsp_gen_interval[lvl - 1] - diff);
1766 else if (lvl == IS_LEVEL_2)
1767 THREAD_TIMER_ON (master, area->t_lsp_refresh[lvl - 1],
1768 lsp_l2_refresh, area,
1769 area->lsp_gen_interval[lvl - 1] - diff);
1770 }
hassof390d2c2004-09-10 20:48:21 +00001771 else
Josh Bailey3f045a02012-03-24 08:35:20 -07001772 {
1773 lsp_regenerate (area, lvl);
1774 }
hassof390d2c2004-09-10 20:48:21 +00001775 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001776
1777 if (all_pseudo)
hassof390d2c2004-09-10 20:48:21 +00001778 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001779 for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit))
1780 lsp_regenerate_schedule_pseudo (circuit, level);
hassof390d2c2004-09-10 20:48:21 +00001781 }
1782
1783 return ISIS_OK;
jardineb5d44e2003-12-23 08:09:43 +00001784}
1785
1786/*
1787 * Funcs for pseudonode LSPs
1788 */
1789
1790/*
1791 * 7.3.8 and 7.3.10 Generation of level 1 and 2 pseudonode LSPs
1792 */
hasso92365882005-01-18 13:53:33 +00001793static void
hassof390d2c2004-09-10 20:48:21 +00001794lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit,
1795 int level)
jardineb5d44e2003-12-23 08:09:43 +00001796{
1797 struct isis_adjacency *adj;
1798 struct is_neigh *is_neigh;
hassoaa4376e2005-09-26 17:39:48 +00001799 struct te_is_neigh *te_is_neigh;
jardineb5d44e2003-12-23 08:09:43 +00001800 struct es_neigh *es_neigh;
1801 struct list *adj_list;
hasso3fdb2dd2005-09-28 18:45:54 +00001802 struct listnode *node;
hassof390d2c2004-09-10 20:48:21 +00001803
jardineb5d44e2003-12-23 08:09:43 +00001804 lsp->level = level;
Josh Bailey3f045a02012-03-24 08:35:20 -07001805 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
1806 if (level == IS_LEVEL_1)
jardineb5d44e2003-12-23 08:09:43 +00001807 lsp->lsp_header->lsp_bits |= IS_LEVEL_1;
1808 else
1809 lsp->lsp_header->lsp_bits |= IS_LEVEL_2;
1810
1811 /*
1812 * add self to IS neighbours
1813 */
hassoaa4376e2005-09-26 17:39:48 +00001814 if (circuit->area->oldmetric)
hassof390d2c2004-09-10 20:48:21 +00001815 {
hassoaa4376e2005-09-26 17:39:48 +00001816 if (lsp->tlv_data.is_neighs == NULL)
1817 {
1818 lsp->tlv_data.is_neighs = list_new ();
1819 lsp->tlv_data.is_neighs->del = free_tlv;
1820 }
1821 is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
paul15935e92005-05-03 09:27:23 +00001822
hassoaa4376e2005-09-26 17:39:48 +00001823 memcpy (&is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN);
1824 listnode_add (lsp->tlv_data.is_neighs, is_neigh);
1825 }
1826 if (circuit->area->newmetric)
1827 {
1828 if (lsp->tlv_data.te_is_neighs == NULL)
1829 {
1830 lsp->tlv_data.te_is_neighs = list_new ();
1831 lsp->tlv_data.te_is_neighs->del = free_tlv;
1832 }
1833 te_is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct te_is_neigh));
1834
1835 memcpy (&te_is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN);
1836 listnode_add (lsp->tlv_data.te_is_neighs, te_is_neigh);
1837 }
hassof390d2c2004-09-10 20:48:21 +00001838
1839 adj_list = list_new ();
1840 isis_adj_build_up_list (circuit->u.bc.adjdb[level - 1], adj_list);
1841
hasso3fdb2dd2005-09-28 18:45:54 +00001842 for (ALL_LIST_ELEMENTS_RO (adj_list, node, adj))
hassof390d2c2004-09-10 20:48:21 +00001843 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001844 if (adj->level & level)
hassof390d2c2004-09-10 20:48:21 +00001845 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001846 if ((level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_L1_IS) ||
1847 (level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_L2_IS &&
hassoaa4376e2005-09-26 17:39:48 +00001848 adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||
Josh Bailey3f045a02012-03-24 08:35:20 -07001849 (level == IS_LEVEL_2 && adj->sys_type == ISIS_SYSTYPE_L2_IS))
hassof390d2c2004-09-10 20:48:21 +00001850 {
1851 /* an IS neighbour -> add it */
hassoaa4376e2005-09-26 17:39:48 +00001852 if (circuit->area->oldmetric)
1853 {
1854 is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
paul15935e92005-05-03 09:27:23 +00001855
hassoaa4376e2005-09-26 17:39:48 +00001856 memcpy (&is_neigh->neigh_id, adj->sysid, ISIS_SYS_ID_LEN);
1857 listnode_add (lsp->tlv_data.is_neighs, is_neigh);
1858 }
1859 if (circuit->area->newmetric)
1860 {
1861 te_is_neigh = XCALLOC (MTYPE_ISIS_TLV,
1862 sizeof (struct te_is_neigh));
1863 memcpy (&te_is_neigh->neigh_id, adj->sysid, ISIS_SYS_ID_LEN);
1864 listnode_add (lsp->tlv_data.te_is_neighs, te_is_neigh);
1865 }
hassof390d2c2004-09-10 20:48:21 +00001866 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001867 else if (level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_ES)
hassof390d2c2004-09-10 20:48:21 +00001868 {
1869 /* an ES neigbour add it, if we are building level 1 LSP */
1870 /* FIXME: the tlv-format is hard to use here */
1871 if (lsp->tlv_data.es_neighs == NULL)
1872 {
1873 lsp->tlv_data.es_neighs = list_new ();
1874 lsp->tlv_data.es_neighs->del = free_tlv;
1875 }
paul15935e92005-05-03 09:27:23 +00001876 es_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct es_neigh));
1877
hassof390d2c2004-09-10 20:48:21 +00001878 memcpy (&es_neigh->first_es_neigh, adj->sysid, ISIS_SYS_ID_LEN);
hassoaac372f2005-09-01 17:52:33 +00001879 listnode_add (lsp->tlv_data.es_neighs, es_neigh);
hassof390d2c2004-09-10 20:48:21 +00001880 }
1881 }
jardineb5d44e2003-12-23 08:09:43 +00001882 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001883 list_delete (adj_list);
hassof390d2c2004-09-10 20:48:21 +00001884
hassoc0fb2a52005-09-03 16:29:40 +00001885 /* Reset endp of stream to overwrite only TLV part of it. */
hassoc89c05d2005-09-04 21:36:36 +00001886 stream_reset (lsp->pdu);
hassoc0fb2a52005-09-03 16:29:40 +00001887 stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
1888
jardineb5d44e2003-12-23 08:09:43 +00001889 /*
1890 * Add the authentication info if it's present
1891 */
Josh Bailey3f045a02012-03-24 08:35:20 -07001892 lsp_auth_add (lsp);
jardineb5d44e2003-12-23 08:09:43 +00001893
1894 if (lsp->tlv_data.is_neighs && listcount (lsp->tlv_data.is_neighs) > 0)
1895 tlv_add_is_neighs (lsp->tlv_data.is_neighs, lsp->pdu);
1896
hassoaa4376e2005-09-26 17:39:48 +00001897 if (lsp->tlv_data.te_is_neighs && listcount (lsp->tlv_data.te_is_neighs) > 0)
1898 tlv_add_te_is_neighs (lsp->tlv_data.te_is_neighs, lsp->pdu);
1899
jardineb5d44e2003-12-23 08:09:43 +00001900 if (lsp->tlv_data.es_neighs && listcount (lsp->tlv_data.es_neighs) > 0)
1901 tlv_add_is_neighs (lsp->tlv_data.es_neighs, lsp->pdu);
1902
paul9985f832005-02-09 15:51:56 +00001903 lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
hassof390d2c2004-09-10 20:48:21 +00001904
Josh Bailey3f045a02012-03-24 08:35:20 -07001905 /* Recompute authentication and checksum information */
1906 lsp_auth_update (lsp);
1907 fletcher_checksum(STREAM_DATA (lsp->pdu) + 12,
1908 ntohs (lsp->lsp_header->pdu_len) - 12, 12);
jardineb5d44e2003-12-23 08:09:43 +00001909
1910 return;
1911}
1912
Josh Bailey3f045a02012-03-24 08:35:20 -07001913int
1914lsp_generate_pseudo (struct isis_circuit *circuit, int level)
jardineb5d44e2003-12-23 08:09:43 +00001915{
1916 dict_t *lspdb = circuit->area->lspdb[level - 1];
1917 struct isis_lsp *lsp;
1918 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
Josh Bailey3f045a02012-03-24 08:35:20 -07001919 u_int16_t rem_lifetime, refresh_time;
1920
1921 if ((circuit->is_type & level) != level ||
1922 (circuit->state != C_STATE_UP) ||
1923 (circuit->circ_type != CIRCUIT_T_BROADCAST) ||
1924 (circuit->u.bc.is_dr[level - 1] == 0))
1925 return ISIS_ERROR;
1926
1927 memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
1928 LSP_FRAGMENT (lsp_id) = 0;
1929 LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id;
1930
1931 /*
1932 * If for some reason have a pseudo LSP in the db already -> regenerate
1933 */
1934 if (lsp_search (lsp_id, lspdb))
1935 return lsp_regenerate_schedule_pseudo (circuit, level);
1936
1937 rem_lifetime = lsp_rem_lifetime (circuit->area, level);
1938 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
1939 lsp = lsp_new (lsp_id, rem_lifetime, 1, circuit->area->is_type, 0, level);
1940 lsp->area = circuit->area;
1941
1942 lsp_build_pseudo (lsp, circuit, level);
1943
1944 lsp->own_lsp = 1;
1945 lsp_insert (lsp, lspdb);
1946 lsp_set_all_srmflags (lsp);
1947
1948 refresh_time = lsp_refresh_time (lsp, rem_lifetime);
1949 THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
1950 circuit->lsp_regenerate_pending[level - 1] = 0;
1951 if (level == IS_LEVEL_1)
1952 THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1],
1953 lsp_l1_refresh_pseudo, circuit, refresh_time);
1954 else if (level == IS_LEVEL_2)
1955 THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1],
1956 lsp_l2_refresh_pseudo, circuit, refresh_time);
1957
1958 if (isis->debugs & DEBUG_UPDATE_PACKETS)
1959 {
1960 zlog_debug ("ISIS-Upd (%s): Building L%d Pseudo LSP %s, len %d, "
1961 "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us",
1962 circuit->area->area_tag, level,
1963 rawlspid_print (lsp->lsp_header->lsp_id),
1964 ntohl (lsp->lsp_header->pdu_len),
1965 ntohl (lsp->lsp_header->seq_num),
1966 ntohs (lsp->lsp_header->checksum),
1967 ntohs (lsp->lsp_header->rem_lifetime),
1968 refresh_time);
1969 }
1970
1971 return ISIS_OK;
1972}
1973
1974static int
1975lsp_regenerate_pseudo (struct isis_circuit *circuit, int level)
1976{
1977 dict_t *lspdb = circuit->area->lspdb[level - 1];
1978 struct isis_lsp *lsp;
1979 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
1980 u_int16_t rem_lifetime, refresh_time;
1981
1982 if ((circuit->is_type & level) != level ||
1983 (circuit->state != C_STATE_UP) ||
1984 (circuit->circ_type != CIRCUIT_T_BROADCAST) ||
1985 (circuit->u.bc.is_dr[level - 1] == 0))
1986 return ISIS_ERROR;
hassof390d2c2004-09-10 20:48:21 +00001987
jardineb5d44e2003-12-23 08:09:43 +00001988 memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
hassof390d2c2004-09-10 20:48:21 +00001989 LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id;
1990 LSP_FRAGMENT (lsp_id) = 0;
1991
jardineb5d44e2003-12-23 08:09:43 +00001992 lsp = lsp_search (lsp_id, lspdb);
hassof390d2c2004-09-10 20:48:21 +00001993
1994 if (!lsp)
1995 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001996 zlog_err ("lsp_regenerate_pseudo: no l%d LSP %s found!",
1997 level, rawlspid_print (lsp_id));
hassof390d2c2004-09-10 20:48:21 +00001998 return ISIS_ERROR;
1999 }
2000 lsp_clear_data (lsp);
jardineb5d44e2003-12-23 08:09:43 +00002001
2002 lsp_build_pseudo (lsp, circuit, level);
2003
Josh Bailey3f045a02012-03-24 08:35:20 -07002004 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
2005 lsp->lsp_header->lsp_bits = circuit->area->is_type;
2006 rem_lifetime = lsp_rem_lifetime (circuit->area, level);
2007 lsp->lsp_header->rem_lifetime = htons (rem_lifetime);
jardineb5d44e2003-12-23 08:09:43 +00002008 lsp_inc_seqnum (lsp, 0);
Josh Bailey3f045a02012-03-24 08:35:20 -07002009 lsp->last_generated = time (NULL);
2010 lsp_set_all_srmflags (lsp);
2011
2012 refresh_time = lsp_refresh_time (lsp, rem_lifetime);
2013 if (level == IS_LEVEL_1)
2014 THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1],
2015 lsp_l1_refresh_pseudo, circuit, refresh_time);
2016 else if (level == IS_LEVEL_2)
2017 THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1],
2018 lsp_l2_refresh_pseudo, circuit, refresh_time);
hassof390d2c2004-09-10 20:48:21 +00002019
2020 if (isis->debugs & DEBUG_UPDATE_PACKETS)
2021 {
Josh Bailey3f045a02012-03-24 08:35:20 -07002022 zlog_debug ("ISIS-Upd (%s): Refreshing L%d Pseudo LSP %s, len %d, "
2023 "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us",
2024 circuit->area->area_tag, level,
2025 rawlspid_print (lsp->lsp_header->lsp_id),
2026 ntohl (lsp->lsp_header->pdu_len),
2027 ntohl (lsp->lsp_header->seq_num),
2028 ntohs (lsp->lsp_header->checksum),
2029 ntohs (lsp->lsp_header->rem_lifetime),
2030 refresh_time);
hassof390d2c2004-09-10 20:48:21 +00002031 }
jardineb5d44e2003-12-23 08:09:43 +00002032
jardineb5d44e2003-12-23 08:09:43 +00002033 return ISIS_OK;
2034}
2035
Josh Bailey3f045a02012-03-24 08:35:20 -07002036/*
2037 * Something has changed or periodic refresh -> regenerate pseudo LSP
2038 */
2039static int
jardineb5d44e2003-12-23 08:09:43 +00002040lsp_l1_refresh_pseudo (struct thread *thread)
2041{
2042 struct isis_circuit *circuit;
Josh Bailey3f045a02012-03-24 08:35:20 -07002043 u_char id[ISIS_SYS_ID_LEN + 2];
jardineb5d44e2003-12-23 08:09:43 +00002044
hassof390d2c2004-09-10 20:48:21 +00002045 circuit = THREAD_ARG (thread);
2046
hasso13c48f72004-09-10 21:19:13 +00002047 circuit->u.bc.t_refresh_pseudo_lsp[0] = NULL;
Josh Bailey3f045a02012-03-24 08:35:20 -07002048 circuit->lsp_regenerate_pending[0] = 0;
hasso13c48f72004-09-10 21:19:13 +00002049
Josh Bailey3f045a02012-03-24 08:35:20 -07002050 if ((circuit->u.bc.is_dr[0] == 0) ||
2051 (circuit->is_type & IS_LEVEL_1) == 0)
2052 {
2053 memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
2054 LSP_PSEUDO_ID (id) = circuit->circuit_id;
2055 LSP_FRAGMENT (id) = 0;
2056 lsp_purge_pseudo (id, circuit, IS_LEVEL_1);
2057 return ISIS_ERROR;
2058 }
hassof390d2c2004-09-10 20:48:21 +00002059
Josh Bailey3f045a02012-03-24 08:35:20 -07002060 return lsp_regenerate_pseudo (circuit, IS_LEVEL_1);
jardineb5d44e2003-12-23 08:09:43 +00002061}
2062
Josh Bailey3f045a02012-03-24 08:35:20 -07002063static int
jardineb5d44e2003-12-23 08:09:43 +00002064lsp_l2_refresh_pseudo (struct thread *thread)
2065{
2066 struct isis_circuit *circuit;
Josh Bailey3f045a02012-03-24 08:35:20 -07002067 u_char id[ISIS_SYS_ID_LEN + 2];
2068
hassof390d2c2004-09-10 20:48:21 +00002069 circuit = THREAD_ARG (thread);
2070
hasso13c48f72004-09-10 21:19:13 +00002071 circuit->u.bc.t_refresh_pseudo_lsp[1] = NULL;
Josh Bailey3f045a02012-03-24 08:35:20 -07002072 circuit->lsp_regenerate_pending[1] = 0;
hasso13c48f72004-09-10 21:19:13 +00002073
Josh Bailey3f045a02012-03-24 08:35:20 -07002074 if ((circuit->u.bc.is_dr[1] == 0) ||
2075 (circuit->is_type & IS_LEVEL_2) == 0)
2076 {
2077 memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
2078 LSP_PSEUDO_ID (id) = circuit->circuit_id;
2079 LSP_FRAGMENT (id) = 0;
2080 lsp_purge_pseudo (id, circuit, IS_LEVEL_2);
2081 return ISIS_ERROR;
2082 }
jardineb5d44e2003-12-23 08:09:43 +00002083
Josh Bailey3f045a02012-03-24 08:35:20 -07002084 return lsp_regenerate_pseudo (circuit, IS_LEVEL_2);
jardineb5d44e2003-12-23 08:09:43 +00002085}
2086
hassof390d2c2004-09-10 20:48:21 +00002087int
Josh Bailey3f045a02012-03-24 08:35:20 -07002088lsp_regenerate_schedule_pseudo (struct isis_circuit *circuit, int level)
jardineb5d44e2003-12-23 08:09:43 +00002089{
2090 struct isis_lsp *lsp;
Josh Bailey3f045a02012-03-24 08:35:20 -07002091 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
2092 time_t now, diff;
2093 int lvl;
jardineb5d44e2003-12-23 08:09:43 +00002094
Josh Bailey3f045a02012-03-24 08:35:20 -07002095 if (circuit == NULL ||
2096 circuit->circ_type != CIRCUIT_T_BROADCAST ||
2097 circuit->state != C_STATE_UP)
2098 return ISIS_OK;
jardineb5d44e2003-12-23 08:09:43 +00002099
Josh Bailey3f045a02012-03-24 08:35:20 -07002100 memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
2101 LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id;
2102 LSP_FRAGMENT (lsp_id) = 0;
2103 now = time (NULL);
jardineb5d44e2003-12-23 08:09:43 +00002104
Josh Bailey3f045a02012-03-24 08:35:20 -07002105 for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++)
2106 {
2107 if (!((level & lvl) && (circuit->is_type & lvl)))
2108 continue;
jardineb5d44e2003-12-23 08:09:43 +00002109
Josh Bailey3f045a02012-03-24 08:35:20 -07002110 if (circuit->u.bc.is_dr[lvl - 1] == 0 ||
2111 circuit->lsp_regenerate_pending[lvl - 1])
2112 continue;
hassof390d2c2004-09-10 20:48:21 +00002113
Josh Bailey3f045a02012-03-24 08:35:20 -07002114 lsp = lsp_search (lsp_id, circuit->area->lspdb[lvl - 1]);
2115 if (!lsp)
2116 continue;
jardineb5d44e2003-12-23 08:09:43 +00002117
Josh Bailey3f045a02012-03-24 08:35:20 -07002118 /*
2119 * Throttle avoidance
2120 */
2121 THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
2122 diff = now - lsp->last_generated;
2123 if (diff < circuit->area->lsp_gen_interval[lvl - 1])
2124 {
2125 circuit->lsp_regenerate_pending[lvl - 1] = 1;
2126 if (lvl == IS_LEVEL_1)
2127 THREAD_TIMER_ON (master,
2128 circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1],
2129 lsp_l1_refresh_pseudo, circuit,
2130 circuit->area->lsp_gen_interval[lvl - 1] - diff);
2131 else if (lvl == IS_LEVEL_2)
2132 THREAD_TIMER_ON (master,
2133 circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1],
2134 lsp_l2_refresh_pseudo, circuit,
2135 circuit->area->lsp_gen_interval[lvl - 1] - diff);
2136 }
2137 else
2138 {
2139 lsp_regenerate_pseudo (circuit, lvl);
2140 }
2141 }
jardineb5d44e2003-12-23 08:09:43 +00002142
Josh Bailey3f045a02012-03-24 08:35:20 -07002143 return ISIS_OK;
jardineb5d44e2003-12-23 08:09:43 +00002144}
2145
jardineb5d44e2003-12-23 08:09:43 +00002146/*
2147 * Walk through LSPs for an area
2148 * - set remaining lifetime
2149 * - set LSPs with SRMflag set for sending
2150 */
hassof390d2c2004-09-10 20:48:21 +00002151int
jardineb5d44e2003-12-23 08:09:43 +00002152lsp_tick (struct thread *thread)
2153{
2154 struct isis_area *area;
2155 struct isis_circuit *circuit;
2156 struct isis_lsp *lsp;
2157 struct list *lsp_list;
hasso3fdb2dd2005-09-28 18:45:54 +00002158 struct listnode *lspnode, *cnode;
jardineb5d44e2003-12-23 08:09:43 +00002159 dnode_t *dnode, *dnode_next;
2160 int level;
Josh Bailey3f045a02012-03-24 08:35:20 -07002161 u_int16_t rem_lifetime;
jardineb5d44e2003-12-23 08:09:43 +00002162
2163 lsp_list = list_new ();
hassof390d2c2004-09-10 20:48:21 +00002164
jardineb5d44e2003-12-23 08:09:43 +00002165 area = THREAD_ARG (thread);
2166 assert (area);
hasso13c48f72004-09-10 21:19:13 +00002167 area->t_tick = NULL;
hassof390d2c2004-09-10 20:48:21 +00002168 THREAD_TIMER_ON (master, area->t_tick, lsp_tick, area, 1);
jardineb5d44e2003-12-23 08:09:43 +00002169
2170 /*
2171 * Build a list of LSPs with (any) SRMflag set
2172 * and removed the ones that have aged out
2173 */
hassof390d2c2004-09-10 20:48:21 +00002174 for (level = 0; level < ISIS_LEVELS; level++)
2175 {
2176 if (area->lspdb[level] && dict_count (area->lspdb[level]) > 0)
Josh Bailey3f045a02012-03-24 08:35:20 -07002177 {
2178 for (dnode = dict_first (area->lspdb[level]);
2179 dnode != NULL; dnode = dnode_next)
2180 {
2181 dnode_next = dict_next (area->lspdb[level], dnode);
2182 lsp = dnode_get (dnode);
jardineb5d44e2003-12-23 08:09:43 +00002183
Josh Bailey3f045a02012-03-24 08:35:20 -07002184 /*
2185 * The lsp rem_lifetime is kept at 0 for MaxAge or
2186 * ZeroAgeLifetime depending on explicit purge or
2187 * natural age out. So schedule spf only once when
2188 * the first time rem_lifetime becomes 0.
2189 */
2190 rem_lifetime = ntohs(lsp->lsp_header->rem_lifetime);
2191 lsp_set_time (lsp);
2192
2193 /*
2194 * Schedule may run spf which should be done only after
2195 * the lsp rem_lifetime becomes 0 for the first time.
2196 * ISO 10589 - 7.3.16.4 first paragraph.
2197 */
2198 if (rem_lifetime == 1 && lsp->lsp_header->seq_num != 0)
2199 {
2200 /* 7.3.16.4 a) set SRM flags on all */
2201 lsp_set_all_srmflags (lsp);
2202 /* 7.3.16.4 b) retain only the header FIXME */
2203 /* 7.3.16.4 c) record the time to purge FIXME */
2204 /* run/schedule spf */
2205 /* isis_spf_schedule is called inside lsp_destroy() below;
2206 * so it is not needed here. */
2207 /* isis_spf_schedule (lsp->area, lsp->level); */
2208 }
2209
2210 if (lsp->age_out == 0)
2211 {
2212 zlog_debug ("ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out",
2213 area->area_tag,
2214 lsp->level,
2215 rawlspid_print (lsp->lsp_header->lsp_id),
2216 ntohl (lsp->lsp_header->seq_num));
hassof1082d12005-09-19 04:23:34 +00002217#ifdef TOPOLOGY_GENERATE
Josh Bailey3f045a02012-03-24 08:35:20 -07002218 if (lsp->from_topology)
2219 THREAD_TIMER_OFF (lsp->t_lsp_top_ref);
hassof1082d12005-09-19 04:23:34 +00002220#endif /* TOPOLOGY_GENERATE */
Josh Bailey3f045a02012-03-24 08:35:20 -07002221 lsp_destroy (lsp);
2222 lsp = NULL;
2223 dict_delete_free (area->lspdb[level], dnode);
2224 }
2225 else if (flags_any_set (lsp->SRMflags))
2226 listnode_add (lsp_list, lsp);
2227 }
jardineb5d44e2003-12-23 08:09:43 +00002228
Josh Bailey3f045a02012-03-24 08:35:20 -07002229 /*
2230 * Send LSPs on circuits indicated by the SRMflags
2231 */
2232 if (listcount (lsp_list) > 0)
2233 {
paul1eb8ef22005-04-07 07:30:20 +00002234 for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit))
Josh Bailey3f045a02012-03-24 08:35:20 -07002235 {
2236 int diff = time (NULL) - circuit->lsp_queue_last_cleared;
2237 if (circuit->lsp_queue == NULL ||
2238 diff < MIN_LSP_TRANS_INTERVAL)
2239 continue;
hasso3fdb2dd2005-09-28 18:45:54 +00002240 for (ALL_LIST_ELEMENTS_RO (lsp_list, lspnode, lsp))
Josh Bailey3f045a02012-03-24 08:35:20 -07002241 {
2242 if (circuit->upadjcount[lsp->level - 1] &&
2243 ISIS_CHECK_FLAG (lsp->SRMflags, circuit))
2244 {
2245 /* Add the lsp only if it is not already in lsp
2246 * queue */
2247 if (! listnode_lookup (circuit->lsp_queue, lsp))
2248 {
2249 listnode_add (circuit->lsp_queue, lsp);
2250 thread_add_event (master, send_lsp, circuit, 0);
2251 }
2252 }
2253 }
2254 }
2255 list_delete_all_node (lsp_list);
2256 }
2257 }
jardineb5d44e2003-12-23 08:09:43 +00002258 }
jardineb5d44e2003-12-23 08:09:43 +00002259
2260 list_delete (lsp_list);
2261
2262 return ISIS_OK;
2263}
2264
jardineb5d44e2003-12-23 08:09:43 +00002265void
Josh Bailey3f045a02012-03-24 08:35:20 -07002266lsp_purge_pseudo (u_char * id, struct isis_circuit *circuit, int level)
jardineb5d44e2003-12-23 08:09:43 +00002267{
2268 struct isis_lsp *lsp;
Josh Bailey3f045a02012-03-24 08:35:20 -07002269 u_int16_t seq_num;
2270 u_int8_t lsp_bits;
hassof390d2c2004-09-10 20:48:21 +00002271
jardineb5d44e2003-12-23 08:09:43 +00002272 lsp = lsp_search (id, circuit->area->lspdb[level - 1]);
Josh Bailey3f045a02012-03-24 08:35:20 -07002273 if (!lsp)
2274 return;
hassof390d2c2004-09-10 20:48:21 +00002275
Josh Bailey3f045a02012-03-24 08:35:20 -07002276 /* store old values */
2277 seq_num = lsp->lsp_header->seq_num;
2278 lsp_bits = lsp->lsp_header->lsp_bits;
2279
2280 /* reset stream */
2281 lsp_clear_data (lsp);
2282 stream_reset (lsp->pdu);
2283
2284 /* update header */
2285 lsp->lsp_header->pdu_len = htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
2286 memcpy (lsp->lsp_header->lsp_id, id, ISIS_SYS_ID_LEN + 2);
2287 lsp->lsp_header->checksum = 0;
2288 lsp->lsp_header->seq_num = seq_num;
2289 lsp->lsp_header->rem_lifetime = 0;
2290 lsp->lsp_header->lsp_bits = lsp_bits;
2291 lsp->level = level;
2292 lsp->age_out = lsp->area->max_lsp_lifetime[level-1];
2293 stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
2294
2295 /*
2296 * Add and update the authentication info if its present
2297 */
2298 lsp_auth_add (lsp);
2299 lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
2300 lsp_auth_update (lsp);
2301 fletcher_checksum(STREAM_DATA (lsp->pdu) + 12,
2302 ntohs (lsp->lsp_header->pdu_len) - 12, 12);
2303
2304 lsp_set_all_srmflags (lsp);
hassof390d2c2004-09-10 20:48:21 +00002305
jardineb5d44e2003-12-23 08:09:43 +00002306 return;
2307}
2308
2309/*
2310 * Purge own LSP that is received and we don't have.
2311 * -> Do as in 7.3.16.4
2312 */
2313void
hassof390d2c2004-09-10 20:48:21 +00002314lsp_purge_non_exist (struct isis_link_state_hdr *lsp_hdr,
2315 struct isis_area *area)
jardineb5d44e2003-12-23 08:09:43 +00002316{
2317 struct isis_lsp *lsp;
2318
2319 /*
2320 * We need to create the LSP to be purged
2321 */
hassoaac372f2005-09-01 17:52:33 +00002322 lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp));
Josh Bailey3f045a02012-03-24 08:35:20 -07002323 lsp->area = area;
jardineb5d44e2003-12-23 08:09:43 +00002324 lsp->level = ((lsp_hdr->lsp_bits & LSPBIT_IST) == IS_LEVEL_1) ? 1 : 2;
Josh Bailey3f045a02012-03-24 08:35:20 -07002325 /* FIXME: Should be minimal mtu? */
2326 lsp->pdu = stream_new (1500);
hassof390d2c2004-09-10 20:48:21 +00002327 lsp->isis_header = (struct isis_fixed_hdr *) STREAM_DATA (lsp->pdu);
Josh Bailey3f045a02012-03-24 08:35:20 -07002328 fill_fixed_hdr (lsp->isis_header, (lsp->level == IS_LEVEL_1) ? L1_LINK_STATE
hassof390d2c2004-09-10 20:48:21 +00002329 : L2_LINK_STATE);
2330 lsp->lsp_header = (struct isis_link_state_hdr *) (STREAM_DATA (lsp->pdu) +
2331 ISIS_FIXED_HDR_LEN);
jardineb5d44e2003-12-23 08:09:43 +00002332 memcpy (lsp->lsp_header, lsp_hdr, ISIS_LSP_HDR_LEN);
Josh Bailey3f045a02012-03-24 08:35:20 -07002333 stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
hassof390d2c2004-09-10 20:48:21 +00002334
jardineb5d44e2003-12-23 08:09:43 +00002335 /*
jardineb5d44e2003-12-23 08:09:43 +00002336 * Set the remaining lifetime to 0
2337 */
2338 lsp->lsp_header->rem_lifetime = 0;
Josh Bailey3f045a02012-03-24 08:35:20 -07002339
2340 /*
2341 * Add and update the authentication info if its present
2342 */
2343 lsp_auth_add (lsp);
2344 lsp_auth_update (lsp);
2345
2346 /*
2347 * Update the PDU length to header plus any authentication TLV.
2348 */
2349 lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
2350
jardineb5d44e2003-12-23 08:09:43 +00002351 /*
2352 * Put the lsp into LSPdb
2353 */
hassof390d2c2004-09-10 20:48:21 +00002354 lsp_insert (lsp, area->lspdb[lsp->level - 1]);
jardineb5d44e2003-12-23 08:09:43 +00002355
2356 /*
2357 * Send in to whole area
2358 */
Josh Bailey3f045a02012-03-24 08:35:20 -07002359 lsp_set_all_srmflags (lsp);
hassof390d2c2004-09-10 20:48:21 +00002360
jardineb5d44e2003-12-23 08:09:43 +00002361 return;
2362}
2363
Josh Bailey3f045a02012-03-24 08:35:20 -07002364void lsp_set_all_srmflags (struct isis_lsp *lsp)
2365{
2366 struct listnode *node;
2367 struct isis_circuit *circuit;
2368
2369 assert (lsp);
2370
2371 ISIS_FLAGS_CLEAR_ALL(lsp->SRMflags);
2372
2373 if (lsp->area)
2374 {
2375 struct list *circuit_list = lsp->area->circuit_list;
2376 for (ALL_LIST_ELEMENTS_RO (circuit_list, node, circuit))
2377 {
2378 ISIS_SET_FLAG(lsp->SRMflags, circuit);
2379 }
2380 }
2381}
2382
jardineb5d44e2003-12-23 08:09:43 +00002383#ifdef TOPOLOGY_GENERATE
hasso92365882005-01-18 13:53:33 +00002384static int
jardineb5d44e2003-12-23 08:09:43 +00002385top_lsp_refresh (struct thread *thread)
2386{
hassof390d2c2004-09-10 20:48:21 +00002387 struct isis_lsp *lsp;
Josh Bailey3f045a02012-03-24 08:35:20 -07002388 u_int16_t rem_lifetime, refresh_time;
jardineb5d44e2003-12-23 08:09:43 +00002389
2390 lsp = THREAD_ARG (thread);
2391 assert (lsp);
2392
2393 lsp->t_lsp_top_ref = NULL;
2394
hassof1082d12005-09-19 04:23:34 +00002395 lsp_seqnum_update (lsp);
jardineb5d44e2003-12-23 08:09:43 +00002396
Josh Bailey3f045a02012-03-24 08:35:20 -07002397 lsp_set_all_srmflags (lsp);
hassof390d2c2004-09-10 20:48:21 +00002398 if (isis->debugs & DEBUG_UPDATE_PACKETS)
2399 {
hasso529d65b2004-12-24 00:14:50 +00002400 zlog_debug ("ISIS-Upd (): refreshing Topology L1 %s",
2401 rawlspid_print (lsp->lsp_header->lsp_id));
hassof390d2c2004-09-10 20:48:21 +00002402 }
hassod3d74742005-09-28 18:30:51 +00002403 /* Refresh dynamic hostname in the cache. */
2404 isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname,
2405 IS_LEVEL_1);
2406
Josh Bailey3f045a02012-03-24 08:35:20 -07002407 lsp->lsp_header->lsp_bits = lsp->area->is_type | lsp->area->overload_bit;
2408 rem_lifetime = lsp_rem_lifetime (lsp->area, IS_LEVEL_1);
2409 lsp->lsp_header->rem_lifetime = htons (rem_lifetime);
jardineb5d44e2003-12-23 08:09:43 +00002410
Josh Bailey3f045a02012-03-24 08:35:20 -07002411 refresh_time = lsp_refresh_time (lsp, rem_lifetime);
hassof390d2c2004-09-10 20:48:21 +00002412 THREAD_TIMER_ON (master, lsp->t_lsp_top_ref, top_lsp_refresh, lsp,
Josh Bailey3f045a02012-03-24 08:35:20 -07002413 lsp->area->lsp_refresh[0]);
jardineb5d44e2003-12-23 08:09:43 +00002414
2415 return ISIS_OK;
2416}
2417
2418void
2419generate_topology_lsps (struct isis_area *area)
2420{
2421 struct listnode *node;
2422 int i, max = 0;
2423 struct arc *arc;
2424 u_char lspid[ISIS_SYS_ID_LEN + 2];
2425 struct isis_lsp *lsp;
Josh Bailey3f045a02012-03-24 08:35:20 -07002426 u_int16_t rem_lifetime, refresh_time;
jardineb5d44e2003-12-23 08:09:43 +00002427
2428 /* first we find the maximal node */
paula8f03df2005-04-10 15:58:10 +00002429 for (ALL_LIST_ELEMENTS_RO (area->topology, node, arc))
Josh Bailey3f045a02012-03-24 08:35:20 -07002430 {
2431 if (arc->from_node > max)
2432 max = arc->from_node;
2433 if (arc->to_node > max)
2434 max = arc->to_node;
2435 }
jardineb5d44e2003-12-23 08:09:43 +00002436
hassof390d2c2004-09-10 20:48:21 +00002437 for (i = 1; i < (max + 1); i++)
2438 {
2439 memcpy (lspid, area->topology_baseis, ISIS_SYS_ID_LEN);
2440 LSP_PSEUDO_ID (lspid) = 0x00;
2441 LSP_FRAGMENT (lspid) = 0x00;
2442 lspid[ISIS_SYS_ID_LEN - 1] = (i & 0xFF);
2443 lspid[ISIS_SYS_ID_LEN - 2] = ((i >> 8) & 0xFF);
jardineb5d44e2003-12-23 08:09:43 +00002444
Josh Bailey3f045a02012-03-24 08:35:20 -07002445 rem_lifetime = lsp_rem_lifetime (area, IS_LEVEL_1);
2446 lsp = lsp_new (lspid, rem_lifetime, 1, IS_LEVEL_1 | area->overload_bit,
2447 0, 1);
hassof1082d12005-09-19 04:23:34 +00002448 if (!lsp)
2449 return;
hassof1082d12005-09-19 04:23:34 +00002450 lsp->area = area;
Josh Bailey3f045a02012-03-24 08:35:20 -07002451 lsp->from_topology = 1;
jardineb5d44e2003-12-23 08:09:43 +00002452
hassof1082d12005-09-19 04:23:34 +00002453 /* Creating LSP data based on topology info. */
2454 build_topology_lsp_data (lsp, area, i);
2455 /* Checksum is also calculated here. */
2456 lsp_seqnum_update (lsp);
hasso9551eea2005-09-28 18:26:25 +00002457 /* Take care of inserting dynamic hostname into cache. */
2458 isis_dynhn_insert (lspid, lsp->tlv_data.hostname, IS_LEVEL_1);
hassof1082d12005-09-19 04:23:34 +00002459
Josh Bailey3f045a02012-03-24 08:35:20 -07002460 refresh_time = lsp_refresh_time (lsp, rem_lifetime);
hassof1082d12005-09-19 04:23:34 +00002461 THREAD_TIMER_ON (master, lsp->t_lsp_top_ref, top_lsp_refresh, lsp,
Josh Bailey3f045a02012-03-24 08:35:20 -07002462 refresh_time);
2463 lsp_set_all_srmflags (lsp);
hassof390d2c2004-09-10 20:48:21 +00002464 lsp_insert (lsp, area->lspdb[0]);
hassof390d2c2004-09-10 20:48:21 +00002465 }
jardineb5d44e2003-12-23 08:09:43 +00002466}
2467
2468void
2469remove_topology_lsps (struct isis_area *area)
2470{
2471 struct isis_lsp *lsp;
2472 dnode_t *dnode, *dnode_next;
2473
2474 dnode = dict_first (area->lspdb[0]);
hassof390d2c2004-09-10 20:48:21 +00002475 while (dnode != NULL)
2476 {
2477 dnode_next = dict_next (area->lspdb[0], dnode);
2478 lsp = dnode_get (dnode);
2479 if (lsp->from_topology)
2480 {
2481 THREAD_TIMER_OFF (lsp->t_lsp_top_ref);
2482 lsp_destroy (lsp);
2483 dict_delete (area->lspdb[0], dnode);
2484 }
2485 dnode = dnode_next;
jardineb5d44e2003-12-23 08:09:43 +00002486 }
jardineb5d44e2003-12-23 08:09:43 +00002487}
2488
2489void
hassof390d2c2004-09-10 20:48:21 +00002490build_topology_lsp_data (struct isis_lsp *lsp, struct isis_area *area,
jardineb5d44e2003-12-23 08:09:43 +00002491 int lsp_top_num)
2492{
hasso3fdb2dd2005-09-28 18:45:54 +00002493 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +00002494 struct arc *arc;
jardineb5d44e2003-12-23 08:09:43 +00002495 struct is_neigh *is_neigh;
hasso9551eea2005-09-28 18:26:25 +00002496 struct te_is_neigh *te_is_neigh;
jardineb5d44e2003-12-23 08:09:43 +00002497 char buff[200];
hassof1082d12005-09-19 04:23:34 +00002498 struct tlvs tlv_data;
2499 struct isis_lsp *lsp0 = lsp;
jardineb5d44e2003-12-23 08:09:43 +00002500
hassof1082d12005-09-19 04:23:34 +00002501 /* Add area addresses. FIXME: Is it needed at all? */
2502 if (lsp->tlv_data.area_addrs == NULL)
2503 lsp->tlv_data.area_addrs = list_new ();
2504 list_add_list (lsp->tlv_data.area_addrs, area->area_addrs);
jardineb5d44e2003-12-23 08:09:43 +00002505
hassof1082d12005-09-19 04:23:34 +00002506 if (lsp->tlv_data.nlpids == NULL)
2507 lsp->tlv_data.nlpids = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct nlpids));
2508 lsp->tlv_data.nlpids->count = 1;
2509 lsp->tlv_data.nlpids->nlpids[0] = NLPID_IP;
jardineb5d44e2003-12-23 08:09:43 +00002510
hassof1082d12005-09-19 04:23:34 +00002511 if (area->dynhostname)
2512 {
2513 lsp->tlv_data.hostname = XMALLOC (MTYPE_ISIS_TLV,
2514 sizeof (struct hostname));
2515 memset (buff, 0x00, 200);
2516 sprintf (buff, "%s%d", area->topology_basedynh ? area->topology_basedynh :
2517 "feedme", lsp_top_num);
2518 memcpy (lsp->tlv_data.hostname->name, buff, strlen (buff));
2519 lsp->tlv_data.hostname->namelen = strlen (buff);
2520 }
2521
2522 if (lsp->tlv_data.nlpids)
2523 tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu);
2524 if (lsp->tlv_data.hostname)
2525 tlv_add_dynamic_hostname (lsp->tlv_data.hostname, lsp->pdu);
2526 if (lsp->tlv_data.area_addrs && listcount (lsp->tlv_data.area_addrs) > 0)
2527 tlv_add_area_addrs (lsp->tlv_data.area_addrs, lsp->pdu);
2528
2529 memset (&tlv_data, 0, sizeof (struct tlvs));
2530 if (tlv_data.is_neighs == NULL)
hasso9551eea2005-09-28 18:26:25 +00002531 {
2532 tlv_data.is_neighs = list_new ();
2533 tlv_data.is_neighs->del = free_tlv;
2534 }
hassof1082d12005-09-19 04:23:34 +00002535
2536 /* Add reachability for this IS for simulated 1. */
hassof390d2c2004-09-10 20:48:21 +00002537 if (lsp_top_num == 1)
2538 {
hasso3fdb2dd2005-09-28 18:45:54 +00002539 is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
hassof1082d12005-09-19 04:23:34 +00002540
hassof390d2c2004-09-10 20:48:21 +00002541 memcpy (&is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN);
jardineb5d44e2003-12-23 08:09:43 +00002542 LSP_PSEUDO_ID (is_neigh->neigh_id) = 0x00;
hassof1082d12005-09-19 04:23:34 +00002543 /* Metric MUST NOT be 0, unless it's not alias TLV. */
2544 is_neigh->metrics.metric_default = 0x01;
jardineb5d44e2003-12-23 08:09:43 +00002545 is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED;
2546 is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED;
2547 is_neigh->metrics.metric_error = METRICS_UNSUPPORTED;
hassof1082d12005-09-19 04:23:34 +00002548 listnode_add (tlv_data.is_neighs, is_neigh);
jardineb5d44e2003-12-23 08:09:43 +00002549 }
hassof390d2c2004-09-10 20:48:21 +00002550
hassof1082d12005-09-19 04:23:34 +00002551 /* Add IS reachabilities. */
hasso3fdb2dd2005-09-28 18:45:54 +00002552 for (ALL_LIST_ELEMENTS_RO (area->topology, node, arc))
hassof390d2c2004-09-10 20:48:21 +00002553 {
hassof1082d12005-09-19 04:23:34 +00002554 int to_lsp = 0;
2555
2556 if ((lsp_top_num != arc->from_node) && (lsp_top_num != arc->to_node))
2557 continue;
2558
2559 if (lsp_top_num == arc->from_node)
2560 to_lsp = arc->to_node;
2561 else
2562 to_lsp = arc->from_node;
2563
hasso9551eea2005-09-28 18:26:25 +00002564 if (area->oldmetric)
2565 {
2566 is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
hassof1082d12005-09-19 04:23:34 +00002567
hasso9551eea2005-09-28 18:26:25 +00002568 memcpy (&is_neigh->neigh_id, area->topology_baseis, ISIS_SYS_ID_LEN);
2569 is_neigh->neigh_id[ISIS_SYS_ID_LEN - 1] = (to_lsp & 0xFF);
2570 is_neigh->neigh_id[ISIS_SYS_ID_LEN - 2] = ((to_lsp >> 8) & 0xFF);
2571 is_neigh->metrics.metric_default = arc->distance;
2572 is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED;
2573 is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED;
2574 is_neigh->metrics.metric_error = METRICS_UNSUPPORTED;
2575 listnode_add (tlv_data.is_neighs, is_neigh);
2576 }
2577
2578 if (area->newmetric)
2579 {
hasso9551eea2005-09-28 18:26:25 +00002580 if (tlv_data.te_is_neighs == NULL)
2581 {
2582 tlv_data.te_is_neighs = list_new ();
2583 tlv_data.te_is_neighs->del = free_tlv;
2584 }
2585 te_is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct te_is_neigh));
2586 memcpy (&te_is_neigh->neigh_id, area->topology_baseis,
2587 ISIS_SYS_ID_LEN);
2588 te_is_neigh->neigh_id[ISIS_SYS_ID_LEN - 1] = (to_lsp & 0xFF);
2589 te_is_neigh->neigh_id[ISIS_SYS_ID_LEN - 2] = ((to_lsp >> 8) & 0xFF);
Josh Bailey3f045a02012-03-24 08:35:20 -07002590 SET_TE_METRIC(te_is_neigh, arc->distance);
hasso9551eea2005-09-28 18:26:25 +00002591 listnode_add (tlv_data.te_is_neighs, te_is_neigh);
2592 }
hassof390d2c2004-09-10 20:48:21 +00002593 }
hassof1082d12005-09-19 04:23:34 +00002594
2595 while (tlv_data.is_neighs && listcount (tlv_data.is_neighs))
2596 {
2597 if (lsp->tlv_data.is_neighs == NULL)
2598 lsp->tlv_data.is_neighs = list_new ();
hasso9551eea2005-09-28 18:26:25 +00002599 lsp_tlv_fit (lsp, &tlv_data.is_neighs, &lsp->tlv_data.is_neighs,
hassof1082d12005-09-19 04:23:34 +00002600 IS_NEIGHBOURS_LEN, area->lsp_frag_threshold,
2601 tlv_add_is_neighs);
2602 if (tlv_data.is_neighs && listcount (tlv_data.is_neighs))
2603 lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
2604 lsp0, area, IS_LEVEL_1);
2605 }
2606
hasso9551eea2005-09-28 18:26:25 +00002607 while (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs))
2608 {
2609 if (lsp->tlv_data.te_is_neighs == NULL)
2610 lsp->tlv_data.te_is_neighs = list_new ();
2611 lsp_tlv_fit (lsp, &tlv_data.te_is_neighs, &lsp->tlv_data.te_is_neighs,
2612 IS_NEIGHBOURS_LEN, area->lsp_frag_threshold,
2613 tlv_add_te_is_neighs);
2614 if (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs))
2615 lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
2616 lsp0, area, IS_LEVEL_1);
2617 }
2618
hassof1082d12005-09-19 04:23:34 +00002619 free_tlvs (&tlv_data);
2620 return;
jardineb5d44e2003-12-23 08:09:43 +00002621}
2622#endif /* TOPOLOGY_GENERATE */