blob: 730924861177226b7ee09d27f7b1a8220433dff4 [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
Christian Frankeacf98652015-11-12 14:24:22 +01008 * Copyright (C) 2013-2015 Christian Franke <chris@opensourcerouting.org>
jardineb5d44e2003-12-23 08:09:43 +00009 *
10 * This program is free software; you can redistribute it and/or modify it
Christian Frankeacf98652015-11-12 14:24:22 +010011 * under the terms of the GNU General Public License as published by the Free
jardineb5d44e2003-12-23 08:09:43 +000012 * Software Foundation; either version 2 of the License, or (at your option)
13 * any later version.
14 *
15 * This program is distributed in the hope that it will be useful,but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 * more details.
19
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 */
paul15935e92005-05-03 09:27:23 +000024
jardineb5d44e2003-12-23 08:09:43 +000025#include <zebra.h>
jardineb5d44e2003-12-23 08:09:43 +000026
27#include "linklist.h"
28#include "thread.h"
29#include "vty.h"
30#include "stream.h"
31#include "memory.h"
32#include "log.h"
33#include "prefix.h"
34#include "command.h"
35#include "hash.h"
36#include "if.h"
Jingjing Duan6a270cd2008-08-13 19:09:10 +010037#include "checksum.h"
Josh Bailey3f045a02012-03-24 08:35:20 -070038#include "md5.h"
Christian Frankeacf98652015-11-12 14:24:22 +010039#include "table.h"
jardineb5d44e2003-12-23 08:09:43 +000040
41#include "isisd/dict.h"
42#include "isisd/isis_constants.h"
43#include "isisd/isis_common.h"
Josh Bailey3f045a02012-03-24 08:35:20 -070044#include "isisd/isis_flags.h"
jardineb5d44e2003-12-23 08:09:43 +000045#include "isisd/isis_circuit.h"
46#include "isisd/isisd.h"
47#include "isisd/isis_tlv.h"
48#include "isisd/isis_lsp.h"
49#include "isisd/isis_pdu.h"
50#include "isisd/isis_dynhn.h"
51#include "isisd/isis_misc.h"
jardineb5d44e2003-12-23 08:09:43 +000052#include "isisd/isis_csm.h"
53#include "isisd/isis_adjacency.h"
54#include "isisd/isis_spf.h"
55
56#ifdef TOPOLOGY_GENERATE
57#include "spgrid.h"
58#endif
59
hasso73d1aea2004-09-24 10:45:28 +000060/* staticly assigned vars for printing purposes */
61char lsp_bits_string[200]; /* FIXME: enough ? */
62
Josh Bailey3f045a02012-03-24 08:35:20 -070063static int lsp_l1_refresh (struct thread *thread);
64static int lsp_l2_refresh (struct thread *thread);
65static int lsp_l1_refresh_pseudo (struct thread *thread);
66static int lsp_l2_refresh_pseudo (struct thread *thread);
67
hassof390d2c2004-09-10 20:48:21 +000068int
69lsp_id_cmp (u_char * id1, u_char * id2)
70{
jardineb5d44e2003-12-23 08:09:43 +000071 return memcmp (id1, id2, ISIS_SYS_ID_LEN + 2);
72}
73
74dict_t *
hassof390d2c2004-09-10 20:48:21 +000075lsp_db_init (void)
jardineb5d44e2003-12-23 08:09:43 +000076{
77 dict_t *dict;
hassof390d2c2004-09-10 20:48:21 +000078
79 dict = dict_create (DICTCOUNT_T_MAX, (dict_comp_t) lsp_id_cmp);
80
jardineb5d44e2003-12-23 08:09:43 +000081 return dict;
82}
83
84struct isis_lsp *
hassof390d2c2004-09-10 20:48:21 +000085lsp_search (u_char * id, dict_t * lspdb)
jardineb5d44e2003-12-23 08:09:43 +000086{
87 dnode_t *node;
88
hassof390d2c2004-09-10 20:48:21 +000089#ifdef EXTREME_DEBUG
jardineb5d44e2003-12-23 08:09:43 +000090 dnode_t *dn;
91
hasso529d65b2004-12-24 00:14:50 +000092 zlog_debug ("searching db");
hassof390d2c2004-09-10 20:48:21 +000093 for (dn = dict_first (lspdb); dn; dn = dict_next (lspdb, dn))
94 {
Josh Bailey3f045a02012-03-24 08:35:20 -070095 zlog_debug ("%s\t%pX", rawlspid_print ((u_char *) dnode_getkey (dn)),
hasso529d65b2004-12-24 00:14:50 +000096 dnode_get (dn));
hassof390d2c2004-09-10 20:48:21 +000097 }
jardineb5d44e2003-12-23 08:09:43 +000098#endif /* EXTREME DEBUG */
99
100 node = dict_lookup (lspdb, id);
hassof390d2c2004-09-10 20:48:21 +0000101
jardineb5d44e2003-12-23 08:09:43 +0000102 if (node)
hassof390d2c2004-09-10 20:48:21 +0000103 return (struct isis_lsp *) dnode_get (node);
jardineb5d44e2003-12-23 08:09:43 +0000104
105 return NULL;
106}
107
hasso92365882005-01-18 13:53:33 +0000108static void
jardineb5d44e2003-12-23 08:09:43 +0000109lsp_clear_data (struct isis_lsp *lsp)
110{
111 if (!lsp)
112 return;
hassof390d2c2004-09-10 20:48:21 +0000113
Josh Bailey3f045a02012-03-24 08:35:20 -0700114 if (lsp->tlv_data.hostname)
115 isis_dynhn_remove (lsp->lsp_header->lsp_id);
116
hassof390d2c2004-09-10 20:48:21 +0000117 if (lsp->own_lsp)
118 {
119 if (lsp->tlv_data.nlpids)
Josh Bailey3f045a02012-03-24 08:35:20 -0700120 XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.nlpids);
hassof390d2c2004-09-10 20:48:21 +0000121 if (lsp->tlv_data.hostname)
Josh Bailey3f045a02012-03-24 08:35:20 -0700122 XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.hostname);
123 if (lsp->tlv_data.router_id)
124 XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.router_id);
hassof390d2c2004-09-10 20:48:21 +0000125 }
jardineb5d44e2003-12-23 08:09:43 +0000126
Josh Bailey3f045a02012-03-24 08:35:20 -0700127 free_tlvs (&lsp->tlv_data);
jardineb5d44e2003-12-23 08:09:43 +0000128}
129
hasso92365882005-01-18 13:53:33 +0000130static void
jardineb5d44e2003-12-23 08:09:43 +0000131lsp_destroy (struct isis_lsp *lsp)
132{
Josh Bailey3f045a02012-03-24 08:35:20 -0700133 struct listnode *cnode, *lnode, *lnnode;
134 struct isis_lsp *lsp_in_list;
135 struct isis_circuit *circuit;
136
jardineb5d44e2003-12-23 08:09:43 +0000137 if (!lsp)
138 return;
hassof390d2c2004-09-10 20:48:21 +0000139
Josh Bailey3f045a02012-03-24 08:35:20 -0700140 for (ALL_LIST_ELEMENTS_RO (lsp->area->circuit_list, cnode, circuit))
141 {
142 if (circuit->lsp_queue == NULL)
143 continue;
144 for (ALL_LIST_ELEMENTS (circuit->lsp_queue, lnode, lnnode, lsp_in_list))
145 if (lsp_in_list == lsp)
146 list_delete_node(circuit->lsp_queue, lnode);
147 }
148 ISIS_FLAGS_CLEAR_ALL (lsp->SSNflags);
149 ISIS_FLAGS_CLEAR_ALL (lsp->SRMflags);
150
jardineb5d44e2003-12-23 08:09:43 +0000151 lsp_clear_data (lsp);
hassof390d2c2004-09-10 20:48:21 +0000152
153 if (LSP_FRAGMENT (lsp->lsp_header->lsp_id) == 0 && lsp->lspu.frags)
154 {
jardineb5d44e2003-12-23 08:09:43 +0000155 list_delete (lsp->lspu.frags);
Josh Bailey3f045a02012-03-24 08:35:20 -0700156 lsp->lspu.frags = NULL;
hassof390d2c2004-09-10 20:48:21 +0000157 }
158
Josh Bailey3f045a02012-03-24 08:35:20 -0700159 isis_spf_schedule (lsp->area, lsp->level);
160#ifdef HAVE_IPV6
161 isis_spf_schedule6 (lsp->area, lsp->level);
162#endif
163
jardineb5d44e2003-12-23 08:09:43 +0000164 if (lsp->pdu)
165 stream_free (lsp->pdu);
166 XFREE (MTYPE_ISIS_LSP, lsp);
167}
168
hassof390d2c2004-09-10 20:48:21 +0000169void
170lsp_db_destroy (dict_t * lspdb)
jardineb5d44e2003-12-23 08:09:43 +0000171{
172 dnode_t *dnode, *next;
173 struct isis_lsp *lsp;
hassof390d2c2004-09-10 20:48:21 +0000174
jardineb5d44e2003-12-23 08:09:43 +0000175 dnode = dict_first (lspdb);
hassof390d2c2004-09-10 20:48:21 +0000176 while (dnode)
177 {
178 next = dict_next (lspdb, dnode);
179 lsp = dnode_get (dnode);
180 lsp_destroy (lsp);
181 dict_delete_free (lspdb, dnode);
182 dnode = next;
183 }
184
jardineb5d44e2003-12-23 08:09:43 +0000185 dict_free (lspdb);
hassof390d2c2004-09-10 20:48:21 +0000186
jardineb5d44e2003-12-23 08:09:43 +0000187 return;
188}
189
190/*
191 * Remove all the frags belonging to the given lsp
192 */
hasso92365882005-01-18 13:53:33 +0000193static void
hassof390d2c2004-09-10 20:48:21 +0000194lsp_remove_frags (struct list *frags, dict_t * lspdb)
jardineb5d44e2003-12-23 08:09:43 +0000195{
196 dnode_t *dnode;
paul1eb8ef22005-04-07 07:30:20 +0000197 struct listnode *lnode, *lnnode;
jardineb5d44e2003-12-23 08:09:43 +0000198 struct isis_lsp *lsp;
199
paul1eb8ef22005-04-07 07:30:20 +0000200 for (ALL_LIST_ELEMENTS (frags, lnode, lnnode, lsp))
hassof390d2c2004-09-10 20:48:21 +0000201 {
hassof390d2c2004-09-10 20:48:21 +0000202 dnode = dict_lookup (lspdb, lsp->lsp_header->lsp_id);
203 lsp_destroy (lsp);
204 dnode_destroy (dict_delete (lspdb, dnode));
205 }
206
jardineb5d44e2003-12-23 08:09:43 +0000207 list_delete_all_node (frags);
hassof390d2c2004-09-10 20:48:21 +0000208
jardineb5d44e2003-12-23 08:09:43 +0000209 return;
210}
211
212void
hassof390d2c2004-09-10 20:48:21 +0000213lsp_search_and_destroy (u_char * id, dict_t * lspdb)
jardineb5d44e2003-12-23 08:09:43 +0000214{
215 dnode_t *node;
216 struct isis_lsp *lsp;
217
218 node = dict_lookup (lspdb, id);
hassof390d2c2004-09-10 20:48:21 +0000219 if (node)
220 {
221 node = dict_delete (lspdb, node);
222 lsp = dnode_get (node);
223 /*
224 * If this is a zero lsp, remove all the frags now
225 */
226 if (LSP_FRAGMENT (lsp->lsp_header->lsp_id) == 0)
227 {
228 if (lsp->lspu.frags)
229 lsp_remove_frags (lsp->lspu.frags, lspdb);
230 }
231 else
232 {
233 /*
234 * else just remove this frag, from the zero lsps' frag list
235 */
236 if (lsp->lspu.zero_lsp && lsp->lspu.zero_lsp->lspu.frags)
237 listnode_delete (lsp->lspu.zero_lsp->lspu.frags, lsp);
238 }
239 lsp_destroy (lsp);
240 dnode_destroy (node);
jardineb5d44e2003-12-23 08:09:43 +0000241 }
jardineb5d44e2003-12-23 08:09:43 +0000242}
243
244/*
245 * Compares a LSP to given values
246 * Params are given in net order
247 */
hassof390d2c2004-09-10 20:48:21 +0000248int
249lsp_compare (char *areatag, struct isis_lsp *lsp, u_int32_t seq_num,
jardineb5d44e2003-12-23 08:09:43 +0000250 u_int16_t checksum, u_int16_t rem_lifetime)
251{
hassof390d2c2004-09-10 20:48:21 +0000252 /* no point in double ntohl on seqnum */
253 if (lsp->lsp_header->seq_num == seq_num &&
jardineb5d44e2003-12-23 08:09:43 +0000254 lsp->lsp_header->checksum == checksum &&
255 /*comparing with 0, no need to do ntohl */
256 ((lsp->lsp_header->rem_lifetime == 0 && rem_lifetime == 0) ||
hassof390d2c2004-09-10 20:48:21 +0000257 (lsp->lsp_header->rem_lifetime != 0 && rem_lifetime != 0)))
258 {
259 if (isis->debugs & DEBUG_SNP_PACKETS)
260 {
Josh Bailey3f045a02012-03-24 08:35:20 -0700261 zlog_debug ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x,"
hasso529d65b2004-12-24 00:14:50 +0000262 " lifetime %us",
263 areatag,
264 rawlspid_print (lsp->lsp_header->lsp_id),
265 ntohl (lsp->lsp_header->seq_num),
266 ntohs (lsp->lsp_header->checksum),
267 ntohs (lsp->lsp_header->rem_lifetime));
268 zlog_debug ("ISIS-Snp (%s): is equal to ours seq 0x%08x,"
269 " cksum 0x%04x, lifetime %us",
270 areatag,
271 ntohl (seq_num), ntohs (checksum), ntohs (rem_lifetime));
hassof390d2c2004-09-10 20:48:21 +0000272 }
273 return LSP_EQUAL;
jardineb5d44e2003-12-23 08:09:43 +0000274 }
jardineb5d44e2003-12-23 08:09:43 +0000275
Christian Franke80d6b4e2015-11-10 18:33:15 +0100276 /*
277 * LSPs with identical checksums should only be treated as newer if:
278 * a) The current LSP has a remaining lifetime != 0 and the other LSP has a
279 * remaining lifetime == 0. In this case, we should participate in the purge
280 * and should not treat the current LSP with remaining lifetime == 0 as older.
281 * b) The LSP has an incorrect checksum. In this case, we need to react as given
282 * in 7.3.16.2.
283 */
284 if (ntohl (seq_num) > ntohl (lsp->lsp_header->seq_num)
285 || (ntohl(seq_num) == ntohl(lsp->lsp_header->seq_num)
286 && ( (lsp->lsp_header->rem_lifetime != 0
287 && rem_lifetime == 0)
288 || lsp->lsp_header->checksum != checksum)))
hassof390d2c2004-09-10 20:48:21 +0000289 {
290 if (isis->debugs & DEBUG_SNP_PACKETS)
291 {
Josh Bailey3f045a02012-03-24 08:35:20 -0700292 zlog_debug ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x,"
hasso529d65b2004-12-24 00:14:50 +0000293 " lifetime %us",
294 areatag,
295 rawlspid_print (lsp->lsp_header->lsp_id),
296 ntohl (seq_num), ntohs (checksum), ntohs (rem_lifetime));
297 zlog_debug ("ISIS-Snp (%s): is newer than ours seq 0x%08x, "
298 "cksum 0x%04x, lifetime %us",
299 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 }
304 return LSP_NEWER;
jardineb5d44e2003-12-23 08:09:43 +0000305 }
hassof390d2c2004-09-10 20:48:21 +0000306 if (isis->debugs & DEBUG_SNP_PACKETS)
307 {
hasso529d65b2004-12-24 00:14:50 +0000308 zlog_debug
Josh Bailey3f045a02012-03-24 08:35:20 -0700309 ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x, lifetime %us",
hassof390d2c2004-09-10 20:48:21 +0000310 areatag, rawlspid_print (lsp->lsp_header->lsp_id), ntohl (seq_num),
311 ntohs (checksum), ntohs (rem_lifetime));
hasso529d65b2004-12-24 00:14:50 +0000312 zlog_debug ("ISIS-Snp (%s): is older than ours seq 0x%08x,"
313 " cksum 0x%04x, lifetime %us", areatag,
314 ntohl (lsp->lsp_header->seq_num),
315 ntohs (lsp->lsp_header->checksum),
316 ntohs (lsp->lsp_header->rem_lifetime));
hassof390d2c2004-09-10 20:48:21 +0000317 }
jardineb5d44e2003-12-23 08:09:43 +0000318
319 return LSP_OLDER;
320}
321
Josh Bailey3f045a02012-03-24 08:35:20 -0700322static void
323lsp_auth_add (struct isis_lsp *lsp)
324{
325 struct isis_passwd *passwd;
326 unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
327
328 /*
329 * Add the authentication info if its present
330 */
331 (lsp->level == IS_LEVEL_1) ? (passwd = &lsp->area->area_passwd) :
332 (passwd = &lsp->area->domain_passwd);
333 switch (passwd->type)
334 {
335 /* Cleartext */
336 case ISIS_PASSWD_TYPE_CLEARTXT:
337 memcpy (&lsp->tlv_data.auth_info, passwd, sizeof (struct isis_passwd));
338 tlv_add_authinfo (passwd->type, passwd->len, passwd->passwd, lsp->pdu);
339 break;
340
341 /* HMAC MD5 */
342 case ISIS_PASSWD_TYPE_HMAC_MD5:
343 /* Remember where TLV is written so we can later
344 * overwrite the MD5 hash */
345 lsp->auth_tlv_offset = stream_get_endp (lsp->pdu);
346 memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
347 lsp->tlv_data.auth_info.type = ISIS_PASSWD_TYPE_HMAC_MD5;
348 lsp->tlv_data.auth_info.len = ISIS_AUTH_MD5_SIZE;
349 memcpy (&lsp->tlv_data.auth_info.passwd, hmac_md5_hash,
350 ISIS_AUTH_MD5_SIZE);
351 tlv_add_authinfo (passwd->type, ISIS_AUTH_MD5_SIZE, hmac_md5_hash,
352 lsp->pdu);
353 break;
354
355 default:
356 break;
357 }
358}
359
360static void
361lsp_auth_update (struct isis_lsp *lsp)
362{
363 struct isis_passwd *passwd;
364 unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
365 uint16_t checksum, rem_lifetime;
366
367 /* For HMAC MD5 we need to recompute the md5 hash and store it */
368 (lsp->level == IS_LEVEL_1) ? (passwd = &lsp->area->area_passwd) :
369 (passwd = &lsp->area->domain_passwd);
370 if (passwd->type != ISIS_PASSWD_TYPE_HMAC_MD5)
371 return;
372
373 /*
374 * In transient conditions (when net is configured where authentication
375 * config and lsp regenerate schedule is not yet run), there could be
376 * an own_lsp with auth_tlv_offset set to 0. In such a case, simply
377 * return, when lsp_regenerate is run, lsp will have auth tlv.
378 */
379 if (lsp->auth_tlv_offset == 0)
380 return;
381
382 /*
383 * RFC 5304 set auth value, checksum and remaining lifetime to zero
384 * before computation and reset to old values after computation.
385 */
386 checksum = lsp->lsp_header->checksum;
387 rem_lifetime = lsp->lsp_header->rem_lifetime;
388 lsp->lsp_header->checksum = 0;
389 lsp->lsp_header->rem_lifetime = 0;
390 /* Set the authentication value as well to zero */
391 memset (STREAM_DATA (lsp->pdu) + lsp->auth_tlv_offset + 3,
392 0, ISIS_AUTH_MD5_SIZE);
393 /* Compute autentication value */
394 hmac_md5 (STREAM_DATA (lsp->pdu), stream_get_endp(lsp->pdu),
395 (unsigned char *) &passwd->passwd, passwd->len,
David Lamparter21401f32015-03-03 08:55:26 +0100396 (unsigned char *) &hmac_md5_hash);
Josh Bailey3f045a02012-03-24 08:35:20 -0700397 /* Copy the hash into the stream */
398 memcpy (STREAM_DATA (lsp->pdu) + lsp->auth_tlv_offset + 3,
399 hmac_md5_hash, ISIS_AUTH_MD5_SIZE);
400 memcpy (&lsp->tlv_data.auth_info.passwd, hmac_md5_hash,
401 ISIS_AUTH_MD5_SIZE);
402 /* Copy back the checksum and remaining lifetime */
403 lsp->lsp_header->checksum = checksum;
404 lsp->lsp_header->rem_lifetime = rem_lifetime;
405}
406
hassof390d2c2004-09-10 20:48:21 +0000407void
jardineb5d44e2003-12-23 08:09:43 +0000408lsp_inc_seqnum (struct isis_lsp *lsp, u_int32_t seq_num)
409{
410 u_int32_t newseq;
hassof390d2c2004-09-10 20:48:21 +0000411
jardineb5d44e2003-12-23 08:09:43 +0000412 if (seq_num == 0 || ntohl (lsp->lsp_header->seq_num) > seq_num)
413 newseq = ntohl (lsp->lsp_header->seq_num) + 1;
414 else
Josh Bailey3f045a02012-03-24 08:35:20 -0700415 newseq = seq_num + 1;
hassof390d2c2004-09-10 20:48:21 +0000416
jardineb5d44e2003-12-23 08:09:43 +0000417 lsp->lsp_header->seq_num = htonl (newseq);
Josh Bailey3f045a02012-03-24 08:35:20 -0700418
419 /* Recompute authentication and checksum information */
420 lsp_auth_update (lsp);
421 /* ISO 10589 - 7.3.11 Generation of the checksum
422 * The checksum shall be computed over all fields in the LSP which appear
423 * after the Remaining Lifetime field. This field (and those appearing
424 * before it) are excluded so that the LSP may be aged by systems without
425 * requiring recomputation.
426 */
427 fletcher_checksum(STREAM_DATA (lsp->pdu) + 12,
428 ntohs (lsp->lsp_header->pdu_len) - 12, 12);
429
430 isis_spf_schedule (lsp->area, lsp->level);
431#ifdef HAVE_IPV6
432 isis_spf_schedule6 (lsp->area, lsp->level);
433#endif
jardineb5d44e2003-12-23 08:09:43 +0000434
435 return;
436}
437
438/*
439 * Genetates checksum for LSP and its frags
440 */
hasso92365882005-01-18 13:53:33 +0000441static void
jardineb5d44e2003-12-23 08:09:43 +0000442lsp_seqnum_update (struct isis_lsp *lsp0)
443{
444 struct isis_lsp *lsp;
hasso3fdb2dd2005-09-28 18:45:54 +0000445 struct listnode *node;
hassof390d2c2004-09-10 20:48:21 +0000446
jardineb5d44e2003-12-23 08:09:43 +0000447 lsp_inc_seqnum (lsp0, 0);
448
449 if (!lsp0->lspu.frags)
450 return;
451
hasso3fdb2dd2005-09-28 18:45:54 +0000452 for (ALL_LIST_ELEMENTS_RO (lsp0->lspu.frags, node, lsp))
paul1eb8ef22005-04-07 07:30:20 +0000453 lsp_inc_seqnum (lsp, 0);
hassof390d2c2004-09-10 20:48:21 +0000454
jardineb5d44e2003-12-23 08:09:43 +0000455 return;
456}
457
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -0700458static u_int8_t
Amritha Nambiarc8ee9402015-08-24 16:40:14 -0700459lsp_bits_generate (int level, int overload_bit, int attached_bit)
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -0700460{
461 u_int8_t lsp_bits = 0;
462 if (level == IS_LEVEL_1)
463 lsp_bits = IS_LEVEL_1;
464 else
465 lsp_bits = IS_LEVEL_1_AND_2;
466 if (overload_bit)
467 lsp_bits |= overload_bit;
Amritha Nambiarc8ee9402015-08-24 16:40:14 -0700468 if (attached_bit)
469 lsp_bits |= attached_bit;
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -0700470 return lsp_bits;
471}
472
hasso92365882005-01-18 13:53:33 +0000473static void
hassof390d2c2004-09-10 20:48:21 +0000474lsp_update_data (struct isis_lsp *lsp, struct stream *stream,
Josh Bailey3f045a02012-03-24 08:35:20 -0700475 struct isis_area *area, int level)
jardineb5d44e2003-12-23 08:09:43 +0000476{
hassof390d2c2004-09-10 20:48:21 +0000477 uint32_t expected = 0, found;
jardineb5d44e2003-12-23 08:09:43 +0000478 int retval;
hassof390d2c2004-09-10 20:48:21 +0000479
Josh Bailey3f045a02012-03-24 08:35:20 -0700480 /* free the old lsp data */
481 lsp_clear_data (lsp);
482
jardineb5d44e2003-12-23 08:09:43 +0000483 /* copying only the relevant part of our stream */
Josh Bailey3f045a02012-03-24 08:35:20 -0700484 if (lsp->pdu != NULL)
485 stream_free (lsp->pdu);
paul15935e92005-05-03 09:27:23 +0000486 lsp->pdu = stream_dup (stream);
Josh Bailey3f045a02012-03-24 08:35:20 -0700487
jardineb5d44e2003-12-23 08:09:43 +0000488 /* setting pointers to the correct place */
hassof390d2c2004-09-10 20:48:21 +0000489 lsp->isis_header = (struct isis_fixed_hdr *) (STREAM_DATA (lsp->pdu));
490 lsp->lsp_header = (struct isis_link_state_hdr *) (STREAM_DATA (lsp->pdu) +
491 ISIS_FIXED_HDR_LEN);
Josh Bailey3f045a02012-03-24 08:35:20 -0700492 lsp->area = area;
493 lsp->level = level;
jardineb5d44e2003-12-23 08:09:43 +0000494 lsp->age_out = ZERO_AGE_LIFETIME;
hassof390d2c2004-09-10 20:48:21 +0000495 lsp->installed = time (NULL);
jardineb5d44e2003-12-23 08:09:43 +0000496 /*
497 * Get LSP data i.e. TLVs
498 */
499 expected |= TLVFLAG_AUTH_INFO;
500 expected |= TLVFLAG_AREA_ADDRS;
501 expected |= TLVFLAG_IS_NEIGHS;
jardineb5d44e2003-12-23 08:09:43 +0000502 expected |= TLVFLAG_NLPID;
503 if (area->dynhostname)
504 expected |= TLVFLAG_DYN_HOSTNAME;
hassof390d2c2004-09-10 20:48:21 +0000505 if (area->newmetric)
506 {
507 expected |= TLVFLAG_TE_IS_NEIGHS;
508 expected |= TLVFLAG_TE_IPV4_REACHABILITY;
509 expected |= TLVFLAG_TE_ROUTER_ID;
510 }
jardineb5d44e2003-12-23 08:09:43 +0000511 expected |= TLVFLAG_IPV4_ADDR;
512 expected |= TLVFLAG_IPV4_INT_REACHABILITY;
513 expected |= TLVFLAG_IPV4_EXT_REACHABILITY;
514#ifdef HAVE_IPV6
515 expected |= TLVFLAG_IPV6_ADDR;
516 expected |= TLVFLAG_IPV6_REACHABILITY;
517#endif /* HAVE_IPV6 */
518
Josh Bailey3f045a02012-03-24 08:35:20 -0700519 retval = parse_tlvs (area->area_tag, STREAM_DATA (lsp->pdu) +
520 ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN,
521 ntohs (lsp->lsp_header->pdu_len) -
522 ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN,
523 &expected, &found, &lsp->tlv_data,
524 NULL);
525 if (retval != ISIS_OK)
hassof390d2c2004-09-10 20:48:21 +0000526 {
Josh Bailey3f045a02012-03-24 08:35:20 -0700527 zlog_warn ("Could not parse LSP");
528 return;
529 }
530
531 if ((found & TLVFLAG_DYN_HOSTNAME) && (area->dynhostname))
532 {
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -0700533 isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname,
534 (lsp->lsp_header->lsp_bits & LSPBIT_IST) ==
535 IS_LEVEL_1_AND_2 ? IS_LEVEL_2 : IS_LEVEL_1);
hassof390d2c2004-09-10 20:48:21 +0000536 }
jardineb5d44e2003-12-23 08:09:43 +0000537
Josh Bailey3f045a02012-03-24 08:35:20 -0700538 return;
jardineb5d44e2003-12-23 08:09:43 +0000539}
540
541void
Josh Bailey3f045a02012-03-24 08:35:20 -0700542lsp_update (struct isis_lsp *lsp, struct stream *stream,
543 struct isis_area *area, int level)
jardineb5d44e2003-12-23 08:09:43 +0000544{
hasso4eda93a2005-09-18 17:51:02 +0000545 dnode_t *dnode = NULL;
hassoa96d8d12005-09-16 14:44:23 +0000546
Josh Bailey3f045a02012-03-24 08:35:20 -0700547 /* Remove old LSP from database. This is required since the
548 * lsp_update_data will free the lsp->pdu (which has the key, lsp_id)
549 * and will update it with the new data in the stream. */
hasso4eda93a2005-09-18 17:51:02 +0000550 dnode = dict_lookup (area->lspdb[level - 1], lsp->lsp_header->lsp_id);
551 if (dnode)
552 dnode_destroy (dict_delete (area->lspdb[level - 1], dnode));
hassoa96d8d12005-09-16 14:44:23 +0000553
jardineb5d44e2003-12-23 08:09:43 +0000554 /* rebuild the lsp data */
Josh Bailey3f045a02012-03-24 08:35:20 -0700555 lsp_update_data (lsp, stream, area, level);
jardineb5d44e2003-12-23 08:09:43 +0000556
Josh Bailey3f045a02012-03-24 08:35:20 -0700557 /* insert the lsp back into the database */
558 lsp_insert (lsp, area->lspdb[level - 1]);
jardineb5d44e2003-12-23 08:09:43 +0000559}
560
jardineb5d44e2003-12-23 08:09:43 +0000561/* creation of LSP directly from what we received */
562struct isis_lsp *
hassof390d2c2004-09-10 20:48:21 +0000563lsp_new_from_stream_ptr (struct stream *stream,
564 u_int16_t pdu_len, struct isis_lsp *lsp0,
Josh Bailey3f045a02012-03-24 08:35:20 -0700565 struct isis_area *area, int level)
jardineb5d44e2003-12-23 08:09:43 +0000566{
567 struct isis_lsp *lsp;
568
hassoaac372f2005-09-01 17:52:33 +0000569 lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp));
Josh Bailey3f045a02012-03-24 08:35:20 -0700570 lsp_update_data (lsp, stream, area, level);
hassof390d2c2004-09-10 20:48:21 +0000571
572 if (lsp0 == NULL)
573 {
574 /*
575 * zero lsp -> create the list for fragments
576 */
577 lsp->lspu.frags = list_new ();
578 }
579 else
580 {
581 /*
582 * a fragment -> set the backpointer and add this to zero lsps frag list
583 */
584 lsp->lspu.zero_lsp = lsp0;
585 listnode_add (lsp0->lspu.frags, lsp);
586 }
587
jardineb5d44e2003-12-23 08:09:43 +0000588 return lsp;
589}
590
591struct isis_lsp *
Christian Frankef1fc1db2015-11-10 18:43:31 +0100592lsp_new(struct isis_area *area, u_char * lsp_id,
593 u_int16_t rem_lifetime, u_int32_t seq_num,
594 u_int8_t lsp_bits, u_int16_t checksum, int level)
jardineb5d44e2003-12-23 08:09:43 +0000595{
596 struct isis_lsp *lsp;
597
hassoaac372f2005-09-01 17:52:33 +0000598 lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp));
Christian Frankef1fc1db2015-11-10 18:43:31 +0100599 lsp->area = area;
Christian Franke390f16e2015-11-10 18:04:44 +0100600
Christian Frankef1fc1db2015-11-10 18:43:31 +0100601 lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu);
jardineb5d44e2003-12-23 08:09:43 +0000602 if (LSP_FRAGMENT (lsp_id) == 0)
603 lsp->lspu.frags = list_new ();
hassof390d2c2004-09-10 20:48:21 +0000604 lsp->isis_header = (struct isis_fixed_hdr *) (STREAM_DATA (lsp->pdu));
605 lsp->lsp_header = (struct isis_link_state_hdr *)
606 (STREAM_DATA (lsp->pdu) + ISIS_FIXED_HDR_LEN);
607
jardineb5d44e2003-12-23 08:09:43 +0000608 /* at first we fill the FIXED HEADER */
Josh Bailey3f045a02012-03-24 08:35:20 -0700609 (level == IS_LEVEL_1) ? fill_fixed_hdr (lsp->isis_header, L1_LINK_STATE) :
hassof390d2c2004-09-10 20:48:21 +0000610 fill_fixed_hdr (lsp->isis_header, L2_LINK_STATE);
611
jardineb5d44e2003-12-23 08:09:43 +0000612 /* now for the LSP HEADER */
613 /* Minimal LSP PDU size */
hassof390d2c2004-09-10 20:48:21 +0000614 lsp->lsp_header->pdu_len = htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
jardineb5d44e2003-12-23 08:09:43 +0000615 memcpy (lsp->lsp_header->lsp_id, lsp_id, ISIS_SYS_ID_LEN + 2);
hassof390d2c2004-09-10 20:48:21 +0000616 lsp->lsp_header->checksum = checksum; /* Provided in network order */
jardineb5d44e2003-12-23 08:09:43 +0000617 lsp->lsp_header->seq_num = htonl (seq_num);
618 lsp->lsp_header->rem_lifetime = htons (rem_lifetime);
619 lsp->lsp_header->lsp_bits = lsp_bits;
620 lsp->level = level;
621 lsp->age_out = ZERO_AGE_LIFETIME;
622
paul9985f832005-02-09 15:51:56 +0000623 stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
jardineb5d44e2003-12-23 08:09:43 +0000624
hassoc89c05d2005-09-04 21:36:36 +0000625 if (isis->debugs & DEBUG_EVENTS)
Josh Bailey3f045a02012-03-24 08:35:20 -0700626 zlog_debug ("New LSP with ID %s-%02x-%02x len %d seqnum %08x",
hassoc89c05d2005-09-04 21:36:36 +0000627 sysid_print (lsp_id), LSP_PSEUDO_ID (lsp->lsp_header->lsp_id),
628 LSP_FRAGMENT (lsp->lsp_header->lsp_id),
Josh Bailey3f045a02012-03-24 08:35:20 -0700629 ntohl (lsp->lsp_header->pdu_len),
hassoc89c05d2005-09-04 21:36:36 +0000630 ntohl (lsp->lsp_header->seq_num));
jardineb5d44e2003-12-23 08:09:43 +0000631
632 return lsp;
633}
634
635void
hassof390d2c2004-09-10 20:48:21 +0000636lsp_insert (struct isis_lsp *lsp, dict_t * lspdb)
jardineb5d44e2003-12-23 08:09:43 +0000637{
638 dict_alloc_insert (lspdb, lsp->lsp_header->lsp_id, lsp);
Josh Bailey3f045a02012-03-24 08:35:20 -0700639 if (lsp->lsp_header->seq_num != 0)
640 {
641 isis_spf_schedule (lsp->area, lsp->level);
642#ifdef HAVE_IPV6
643 isis_spf_schedule6 (lsp->area, lsp->level);
644#endif
645 }
jardineb5d44e2003-12-23 08:09:43 +0000646}
647
648/*
649 * Build a list of LSPs with non-zero ht bounded by start and stop ids
650 */
hassof390d2c2004-09-10 20:48:21 +0000651void
652lsp_build_list_nonzero_ht (u_char * start_id, u_char * stop_id,
653 struct list *list, dict_t * lspdb)
jardineb5d44e2003-12-23 08:09:43 +0000654{
655 dnode_t *first, *last, *curr;
656
657 first = dict_lower_bound (lspdb, start_id);
658 if (!first)
659 return;
hassof390d2c2004-09-10 20:48:21 +0000660
jardineb5d44e2003-12-23 08:09:43 +0000661 last = dict_upper_bound (lspdb, stop_id);
hassof390d2c2004-09-10 20:48:21 +0000662
jardineb5d44e2003-12-23 08:09:43 +0000663 curr = first;
hassof390d2c2004-09-10 20:48:21 +0000664
665 if (((struct isis_lsp *) (curr->dict_data))->lsp_header->rem_lifetime)
jardineb5d44e2003-12-23 08:09:43 +0000666 listnode_add (list, first->dict_data);
667
hassof390d2c2004-09-10 20:48:21 +0000668 while (curr)
669 {
670 curr = dict_next (lspdb, curr);
671 if (curr &&
672 ((struct isis_lsp *) (curr->dict_data))->lsp_header->rem_lifetime)
673 listnode_add (list, curr->dict_data);
674 if (curr == last)
675 break;
676 }
677
jardineb5d44e2003-12-23 08:09:43 +0000678 return;
679}
680
681/*
Josh Bailey3f045a02012-03-24 08:35:20 -0700682 * Build a list of num_lsps LSPs bounded by start_id and stop_id.
jardineb5d44e2003-12-23 08:09:43 +0000683 */
hassof390d2c2004-09-10 20:48:21 +0000684void
Josh Bailey3f045a02012-03-24 08:35:20 -0700685lsp_build_list (u_char * start_id, u_char * stop_id, u_char num_lsps,
hassof390d2c2004-09-10 20:48:21 +0000686 struct list *list, dict_t * lspdb)
jardineb5d44e2003-12-23 08:09:43 +0000687{
Josh Bailey3f045a02012-03-24 08:35:20 -0700688 u_char count;
jardineb5d44e2003-12-23 08:09:43 +0000689 dnode_t *first, *last, *curr;
690
691 first = dict_lower_bound (lspdb, start_id);
692 if (!first)
693 return;
hassof390d2c2004-09-10 20:48:21 +0000694
jardineb5d44e2003-12-23 08:09:43 +0000695 last = dict_upper_bound (lspdb, stop_id);
hassof390d2c2004-09-10 20:48:21 +0000696
jardineb5d44e2003-12-23 08:09:43 +0000697 curr = first;
hassof390d2c2004-09-10 20:48:21 +0000698
jardineb5d44e2003-12-23 08:09:43 +0000699 listnode_add (list, first->dict_data);
Josh Bailey3f045a02012-03-24 08:35:20 -0700700 count = 1;
jardineb5d44e2003-12-23 08:09:43 +0000701
hassof390d2c2004-09-10 20:48:21 +0000702 while (curr)
703 {
704 curr = dict_next (lspdb, curr);
705 if (curr)
Josh Bailey3f045a02012-03-24 08:35:20 -0700706 {
707 listnode_add (list, curr->dict_data);
708 count++;
709 }
710 if (count == num_lsps || curr == last)
711 break;
hassof390d2c2004-09-10 20:48:21 +0000712 }
713
jardineb5d44e2003-12-23 08:09:43 +0000714 return;
715}
716
717/*
718 * Build a list of LSPs with SSN flag set for the given circuit
719 */
720void
Josh Bailey3f045a02012-03-24 08:35:20 -0700721lsp_build_list_ssn (struct isis_circuit *circuit, u_char num_lsps,
722 struct list *list, dict_t * lspdb)
jardineb5d44e2003-12-23 08:09:43 +0000723{
724 dnode_t *dnode, *next;
725 struct isis_lsp *lsp;
Josh Bailey3f045a02012-03-24 08:35:20 -0700726 u_char count = 0;
hassof390d2c2004-09-10 20:48:21 +0000727
jardineb5d44e2003-12-23 08:09:43 +0000728 dnode = dict_first (lspdb);
hassof390d2c2004-09-10 20:48:21 +0000729 while (dnode != NULL)
730 {
731 next = dict_next (lspdb, dnode);
732 lsp = dnode_get (dnode);
733 if (ISIS_CHECK_FLAG (lsp->SSNflags, circuit))
Josh Bailey3f045a02012-03-24 08:35:20 -0700734 {
735 listnode_add (list, lsp);
736 ++count;
737 }
738 if (count == num_lsps)
739 break;
hassof390d2c2004-09-10 20:48:21 +0000740 dnode = next;
741 }
742
jardineb5d44e2003-12-23 08:09:43 +0000743 return;
744}
745
hasso92365882005-01-18 13:53:33 +0000746static void
jardineb5d44e2003-12-23 08:09:43 +0000747lsp_set_time (struct isis_lsp *lsp)
748{
749 assert (lsp);
hassof390d2c2004-09-10 20:48:21 +0000750
751 if (lsp->lsp_header->rem_lifetime == 0)
752 {
Josh Bailey3f045a02012-03-24 08:35:20 -0700753 if (lsp->age_out > 0)
754 lsp->age_out--;
hassof390d2c2004-09-10 20:48:21 +0000755 return;
756 }
jardineb5d44e2003-12-23 08:09:43 +0000757
hassof390d2c2004-09-10 20:48:21 +0000758 lsp->lsp_header->rem_lifetime =
jardineb5d44e2003-12-23 08:09:43 +0000759 htons (ntohs (lsp->lsp_header->rem_lifetime) - 1);
760}
761
hasso92365882005-01-18 13:53:33 +0000762static void
hassof390d2c2004-09-10 20:48:21 +0000763lspid_print (u_char * lsp_id, u_char * trg, char dynhost, char frag)
jardineb5d44e2003-12-23 08:09:43 +0000764{
765 struct isis_dynhn *dyn = NULL;
hassof390d2c2004-09-10 20:48:21 +0000766 u_char id[SYSID_STRLEN];
jardineb5d44e2003-12-23 08:09:43 +0000767
768 if (dynhost)
769 dyn = dynhn_find_by_id (lsp_id);
770 else
771 dyn = NULL;
772
773 if (dyn)
Josh Bailey3f045a02012-03-24 08:35:20 -0700774 sprintf ((char *)id, "%.14s", dyn->name.name);
775 else if (!memcmp (isis->sysid, lsp_id, ISIS_SYS_ID_LEN) && dynhost)
776 sprintf ((char *)id, "%.14s", unix_hostname ());
jardineb5d44e2003-12-23 08:09:43 +0000777 else
hassof390d2c2004-09-10 20:48:21 +0000778 memcpy (id, sysid_print (lsp_id), 15);
hassof390d2c2004-09-10 20:48:21 +0000779 if (frag)
hassof7c43dc2004-09-26 16:24:14 +0000780 sprintf ((char *)trg, "%s.%02x-%02x", id, LSP_PSEUDO_ID (lsp_id),
hassof390d2c2004-09-10 20:48:21 +0000781 LSP_FRAGMENT (lsp_id));
782 else
hassof7c43dc2004-09-26 16:24:14 +0000783 sprintf ((char *)trg, "%s.%02x", id, LSP_PSEUDO_ID (lsp_id));
jardineb5d44e2003-12-23 08:09:43 +0000784}
785
hassof390d2c2004-09-10 20:48:21 +0000786/* Convert the lsp attribute bits to attribute string */
hasso1cd80842004-10-07 20:07:40 +0000787const char *
hassof390d2c2004-09-10 20:48:21 +0000788lsp_bits2string (u_char * lsp_bits)
789{
790 char *pos = lsp_bits_string;
jardineb5d44e2003-12-23 08:09:43 +0000791
hassof390d2c2004-09-10 20:48:21 +0000792 if (!*lsp_bits)
jardineb5d44e2003-12-23 08:09:43 +0000793 return " none";
794
795 /* we only focus on the default metric */
796 pos += sprintf (pos, "%d/",
hassof390d2c2004-09-10 20:48:21 +0000797 ISIS_MASK_LSP_ATT_DEFAULT_BIT (*lsp_bits) ? 1 : 0);
jardineb5d44e2003-12-23 08:09:43 +0000798
799 pos += sprintf (pos, "%d/",
hassof390d2c2004-09-10 20:48:21 +0000800 ISIS_MASK_LSP_PARTITION_BIT (*lsp_bits) ? 1 : 0);
jardineb5d44e2003-12-23 08:09:43 +0000801
hassof390d2c2004-09-10 20:48:21 +0000802 pos += sprintf (pos, "%d", ISIS_MASK_LSP_OL_BIT (*lsp_bits) ? 1 : 0);
803
jardineb5d44e2003-12-23 08:09:43 +0000804 *(pos) = '\0';
jardineb5d44e2003-12-23 08:09:43 +0000805
hassof390d2c2004-09-10 20:48:21 +0000806 return lsp_bits_string;
jardineb5d44e2003-12-23 08:09:43 +0000807}
808
809/* this function prints the lsp on show isis database */
Josh Bailey3f045a02012-03-24 08:35:20 -0700810void
811lsp_print (struct isis_lsp *lsp, struct vty *vty, char dynhost)
jardineb5d44e2003-12-23 08:09:43 +0000812{
jardineb5d44e2003-12-23 08:09:43 +0000813 u_char LSPid[255];
Josh Bailey3f045a02012-03-24 08:35:20 -0700814 char age_out[8];
jardineb5d44e2003-12-23 08:09:43 +0000815
816 lspid_print (lsp->lsp_header->lsp_id, LSPid, dynhost, 1);
Josh Bailey3f045a02012-03-24 08:35:20 -0700817 vty_out (vty, "%-21s%c ", LSPid, lsp->own_lsp ? '*' : ' ');
818 vty_out (vty, "%5u ", ntohs (lsp->lsp_header->pdu_len));
819 vty_out (vty, "0x%08x ", ntohl (lsp->lsp_header->seq_num));
820 vty_out (vty, "0x%04x ", ntohs (lsp->lsp_header->checksum));
hassof390d2c2004-09-10 20:48:21 +0000821 if (ntohs (lsp->lsp_header->rem_lifetime) == 0)
Josh Bailey3f045a02012-03-24 08:35:20 -0700822 {
823 snprintf (age_out, 8, "(%u)", lsp->age_out);
824 age_out[7] = '\0';
825 vty_out (vty, "%7s ", age_out);
826 }
jardineb5d44e2003-12-23 08:09:43 +0000827 else
Josh Bailey3f045a02012-03-24 08:35:20 -0700828 vty_out (vty, " %5u ", ntohs (lsp->lsp_header->rem_lifetime));
829 vty_out (vty, "%s%s",
830 lsp_bits2string (&lsp->lsp_header->lsp_bits), VTY_NEWLINE);
jardineb5d44e2003-12-23 08:09:43 +0000831}
832
Josh Bailey3f045a02012-03-24 08:35:20 -0700833void
834lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost)
jardineb5d44e2003-12-23 08:09:43 +0000835{
jardineb5d44e2003-12-23 08:09:43 +0000836 struct area_addr *area_addr;
hassof390d2c2004-09-10 20:48:21 +0000837 int i;
hasso3fdb2dd2005-09-28 18:45:54 +0000838 struct listnode *lnode;
jardineb5d44e2003-12-23 08:09:43 +0000839 struct is_neigh *is_neigh;
840 struct te_is_neigh *te_is_neigh;
841 struct ipv4_reachability *ipv4_reach;
842 struct in_addr *ipv4_addr;
843 struct te_ipv4_reachability *te_ipv4_reach;
844#ifdef HAVE_IPV6
845 struct ipv6_reachability *ipv6_reach;
846 struct in6_addr in6;
Paul Jakma41b36e92006-12-08 01:09:50 +0000847 u_char buff[BUFSIZ];
jardineb5d44e2003-12-23 08:09:43 +0000848#endif
849 u_char LSPid[255];
850 u_char hostname[255];
jardineb5d44e2003-12-23 08:09:43 +0000851 u_char ipv4_reach_prefix[20];
852 u_char ipv4_reach_mask[20];
853 u_char ipv4_address[20];
854
855 lspid_print (lsp->lsp_header->lsp_id, LSPid, dynhost, 1);
Josh Bailey3f045a02012-03-24 08:35:20 -0700856 lsp_print (lsp, vty, dynhost);
jardineb5d44e2003-12-23 08:09:43 +0000857
858 /* for all area address */
hassof390d2c2004-09-10 20:48:21 +0000859 if (lsp->tlv_data.area_addrs)
hasso3fdb2dd2005-09-28 18:45:54 +0000860 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.area_addrs, lnode, area_addr))
hassof390d2c2004-09-10 20:48:21 +0000861 {
hasso1cd80842004-10-07 20:07:40 +0000862 vty_out (vty, " Area Address: %s%s",
hassof390d2c2004-09-10 20:48:21 +0000863 isonet_print (area_addr->area_addr, area_addr->addr_len),
864 VTY_NEWLINE);
865 }
paul1eb8ef22005-04-07 07:30:20 +0000866
jardineb5d44e2003-12-23 08:09:43 +0000867 /* for the nlpid tlv */
hassof390d2c2004-09-10 20:48:21 +0000868 if (lsp->tlv_data.nlpids)
869 {
870 for (i = 0; i < lsp->tlv_data.nlpids->count; i++)
871 {
872 switch (lsp->tlv_data.nlpids->nlpids[i])
873 {
874 case NLPID_IP:
875 case NLPID_IPV6:
Josh Bailey3f045a02012-03-24 08:35:20 -0700876 vty_out (vty, " NLPID : 0x%X%s",
hassof390d2c2004-09-10 20:48:21 +0000877 lsp->tlv_data.nlpids->nlpids[i], VTY_NEWLINE);
878 break;
879 default:
Josh Bailey3f045a02012-03-24 08:35:20 -0700880 vty_out (vty, " NLPID : %s%s", "unknown", VTY_NEWLINE);
hassof390d2c2004-09-10 20:48:21 +0000881 break;
882 }
883 }
884 }
jardineb5d44e2003-12-23 08:09:43 +0000885
886 /* for the hostname tlv */
hassof390d2c2004-09-10 20:48:21 +0000887 if (lsp->tlv_data.hostname)
888 {
Josh Bailey3f045a02012-03-24 08:35:20 -0700889 bzero (hostname, sizeof (hostname));
hassof390d2c2004-09-10 20:48:21 +0000890 memcpy (hostname, lsp->tlv_data.hostname->name,
891 lsp->tlv_data.hostname->namelen);
Josh Bailey3f045a02012-03-24 08:35:20 -0700892 vty_out (vty, " Hostname : %s%s", hostname, VTY_NEWLINE);
jardineb5d44e2003-12-23 08:09:43 +0000893 }
hassof390d2c2004-09-10 20:48:21 +0000894
Josh Bailey3f045a02012-03-24 08:35:20 -0700895 /* authentication tlv */
896 if (lsp->tlv_data.auth_info.type != ISIS_PASSWD_TYPE_UNUSED)
897 {
898 if (lsp->tlv_data.auth_info.type == ISIS_PASSWD_TYPE_HMAC_MD5)
899 vty_out (vty, " Auth type : md5%s", VTY_NEWLINE);
900 else if (lsp->tlv_data.auth_info.type == ISIS_PASSWD_TYPE_CLEARTXT)
901 vty_out (vty, " Auth type : clear text%s", VTY_NEWLINE);
902 }
hassof390d2c2004-09-10 20:48:21 +0000903
hasso1cd80842004-10-07 20:07:40 +0000904 /* TE router id */
905 if (lsp->tlv_data.router_id)
906 {
907 memcpy (ipv4_address, inet_ntoa (lsp->tlv_data.router_id->id),
908 sizeof (ipv4_address));
Josh Bailey3f045a02012-03-24 08:35:20 -0700909 vty_out (vty, " Router ID : %s%s", ipv4_address, VTY_NEWLINE);
hasso1cd80842004-10-07 20:07:40 +0000910 }
911
Josh Bailey3f045a02012-03-24 08:35:20 -0700912 if (lsp->tlv_data.ipv4_addrs)
913 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_addrs, lnode, ipv4_addr))
914 {
915 memcpy (ipv4_address, inet_ntoa (*ipv4_addr), sizeof (ipv4_address));
916 vty_out (vty, " IPv4 Address: %s%s", ipv4_address, VTY_NEWLINE);
917 }
918
hasso1cd80842004-10-07 20:07:40 +0000919 /* for the IS neighbor tlv */
920 if (lsp->tlv_data.is_neighs)
hasso3fdb2dd2005-09-28 18:45:54 +0000921 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, lnode, is_neigh))
hasso1cd80842004-10-07 20:07:40 +0000922 {
923 lspid_print (is_neigh->neigh_id, LSPid, dynhost, 0);
Josh Bailey3f045a02012-03-24 08:35:20 -0700924 vty_out (vty, " Metric : %-8d IS : %s%s",
hasso1cd80842004-10-07 20:07:40 +0000925 is_neigh->metrics.metric_default, LSPid, VTY_NEWLINE);
926 }
hasso1cd80842004-10-07 20:07:40 +0000927
jardineb5d44e2003-12-23 08:09:43 +0000928 /* for the internal reachable tlv */
929 if (lsp->tlv_data.ipv4_int_reachs)
hasso3fdb2dd2005-09-28 18:45:54 +0000930 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_int_reachs, lnode,
931 ipv4_reach))
hassof390d2c2004-09-10 20:48:21 +0000932 {
933 memcpy (ipv4_reach_prefix, inet_ntoa (ipv4_reach->prefix),
934 sizeof (ipv4_reach_prefix));
935 memcpy (ipv4_reach_mask, inet_ntoa (ipv4_reach->mask),
936 sizeof (ipv4_reach_mask));
Josh Bailey3f045a02012-03-24 08:35:20 -0700937 vty_out (vty, " Metric : %-8d IPv4-Internal : %s %s%s",
hassof390d2c2004-09-10 20:48:21 +0000938 ipv4_reach->metrics.metric_default, ipv4_reach_prefix,
939 ipv4_reach_mask, VTY_NEWLINE);
940 }
hasso2097cd82003-12-23 11:51:08 +0000941
942 /* for the external reachable tlv */
943 if (lsp->tlv_data.ipv4_ext_reachs)
hasso3fdb2dd2005-09-28 18:45:54 +0000944 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_ext_reachs, lnode,
945 ipv4_reach))
hassof390d2c2004-09-10 20:48:21 +0000946 {
947 memcpy (ipv4_reach_prefix, inet_ntoa (ipv4_reach->prefix),
948 sizeof (ipv4_reach_prefix));
949 memcpy (ipv4_reach_mask, inet_ntoa (ipv4_reach->mask),
950 sizeof (ipv4_reach_mask));
Josh Bailey3f045a02012-03-24 08:35:20 -0700951 vty_out (vty, " Metric : %-8d IPv4-External : %s %s%s",
hassof390d2c2004-09-10 20:48:21 +0000952 ipv4_reach->metrics.metric_default, ipv4_reach_prefix,
953 ipv4_reach_mask, VTY_NEWLINE);
954 }
paul1eb8ef22005-04-07 07:30:20 +0000955
hasso2097cd82003-12-23 11:51:08 +0000956 /* IPv6 tlv */
957#ifdef HAVE_IPV6
958 if (lsp->tlv_data.ipv6_reachs)
hasso3fdb2dd2005-09-28 18:45:54 +0000959 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv6_reachs, lnode, ipv6_reach))
hassof390d2c2004-09-10 20:48:21 +0000960 {
961 memset (&in6, 0, sizeof (in6));
962 memcpy (in6.s6_addr, ipv6_reach->prefix,
963 PSIZE (ipv6_reach->prefix_len));
hassof7c43dc2004-09-26 16:24:14 +0000964 inet_ntop (AF_INET6, &in6, (char *)buff, BUFSIZ);
David Lamparter6db3ef62015-03-03 09:07:43 +0100965 if ((ipv6_reach->control_info &
hassof390d2c2004-09-10 20:48:21 +0000966 CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL)
Josh Bailey3f045a02012-03-24 08:35:20 -0700967 vty_out (vty, " Metric : %-8d IPv6-Internal : %s/%d%s",
hassof390d2c2004-09-10 20:48:21 +0000968 ntohl (ipv6_reach->metric),
969 buff, ipv6_reach->prefix_len, VTY_NEWLINE);
hasso2097cd82003-12-23 11:51:08 +0000970 else
Josh Bailey3f045a02012-03-24 08:35:20 -0700971 vty_out (vty, " Metric : %-8d IPv6-External : %s/%d%s",
hassof390d2c2004-09-10 20:48:21 +0000972 ntohl (ipv6_reach->metric),
973 buff, ipv6_reach->prefix_len, VTY_NEWLINE);
hasso2097cd82003-12-23 11:51:08 +0000974 }
975#endif
paul1eb8ef22005-04-07 07:30:20 +0000976
hasso1cd80842004-10-07 20:07:40 +0000977 /* TE IS neighbor tlv */
jardineb5d44e2003-12-23 08:09:43 +0000978 if (lsp->tlv_data.te_is_neighs)
hasso3fdb2dd2005-09-28 18:45:54 +0000979 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, lnode, te_is_neigh))
hassof390d2c2004-09-10 20:48:21 +0000980 {
hassof390d2c2004-09-10 20:48:21 +0000981 lspid_print (te_is_neigh->neigh_id, LSPid, dynhost, 0);
Josh Bailey3f045a02012-03-24 08:35:20 -0700982 vty_out (vty, " Metric : %-8d IS-Extended : %s%s",
983 GET_TE_METRIC(te_is_neigh), LSPid, VTY_NEWLINE);
hassof390d2c2004-09-10 20:48:21 +0000984 }
jardineb5d44e2003-12-23 08:09:43 +0000985
hasso1cd80842004-10-07 20:07:40 +0000986 /* TE IPv4 tlv */
jardineb5d44e2003-12-23 08:09:43 +0000987 if (lsp->tlv_data.te_ipv4_reachs)
hasso3fdb2dd2005-09-28 18:45:54 +0000988 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_ipv4_reachs, lnode,
989 te_ipv4_reach))
hassof390d2c2004-09-10 20:48:21 +0000990 {
hasso1cd80842004-10-07 20:07:40 +0000991 /* FIXME: There should be better way to output this stuff. */
Josh Bailey3f045a02012-03-24 08:35:20 -0700992 vty_out (vty, " Metric : %-8d IPv4-Extended : %s/%d%s",
hasso1cd80842004-10-07 20:07:40 +0000993 ntohl (te_ipv4_reach->te_metric),
hassof390d2c2004-09-10 20:48:21 +0000994 inet_ntoa (newprefix2inaddr (&te_ipv4_reach->prefix_start,
995 te_ipv4_reach->control)),
hasso1cd80842004-10-07 20:07:40 +0000996 te_ipv4_reach->control & 0x3F, VTY_NEWLINE);
hassof390d2c2004-09-10 20:48:21 +0000997 }
Josh Bailey3f045a02012-03-24 08:35:20 -0700998 vty_out (vty, "%s", VTY_NEWLINE);
jardineb5d44e2003-12-23 08:09:43 +0000999
hassof390d2c2004-09-10 20:48:21 +00001000 return;
jardineb5d44e2003-12-23 08:09:43 +00001001}
1002
1003/* print all the lsps info in the local lspdb */
hassof390d2c2004-09-10 20:48:21 +00001004int
1005lsp_print_all (struct vty *vty, dict_t * lspdb, char detail, char dynhost)
jardineb5d44e2003-12-23 08:09:43 +00001006{
1007
hassof390d2c2004-09-10 20:48:21 +00001008 dnode_t *node = dict_first (lspdb), *next;
jardineb5d44e2003-12-23 08:09:43 +00001009 int lsp_count = 0;
1010
hassof390d2c2004-09-10 20:48:21 +00001011 if (detail == ISIS_UI_LEVEL_BRIEF)
1012 {
1013 while (node != NULL)
1014 {
1015 /* I think it is unnecessary, so I comment it out */
1016 /* dict_contains (lspdb, node); */
1017 next = dict_next (lspdb, node);
Josh Bailey3f045a02012-03-24 08:35:20 -07001018 lsp_print (dnode_get (node), vty, dynhost);
hassof390d2c2004-09-10 20:48:21 +00001019 node = next;
1020 lsp_count++;
1021 }
jardineb5d44e2003-12-23 08:09:43 +00001022 }
hassof390d2c2004-09-10 20:48:21 +00001023 else if (detail == ISIS_UI_LEVEL_DETAIL)
1024 {
1025 while (node != NULL)
1026 {
1027 next = dict_next (lspdb, node);
Josh Bailey3f045a02012-03-24 08:35:20 -07001028 lsp_print_detail (dnode_get (node), vty, dynhost);
hassof390d2c2004-09-10 20:48:21 +00001029 node = next;
1030 lsp_count++;
1031 }
jardineb5d44e2003-12-23 08:09:43 +00001032 }
jardineb5d44e2003-12-23 08:09:43 +00001033
1034 return lsp_count;
1035}
1036
jardineb5d44e2003-12-23 08:09:43 +00001037#define FRAG_THOLD(S,T) \
Josh Bailey3f045a02012-03-24 08:35:20 -07001038 ((STREAM_SIZE(S)*T)/100)
jardineb5d44e2003-12-23 08:09:43 +00001039
1040/* stream*, area->lsp_frag_threshold, increment */
1041#define FRAG_NEEDED(S,T,I) \
1042 (STREAM_SIZE(S)-STREAM_REMAIN(S)+(I) > FRAG_THOLD(S,T))
1043
hassoaa4376e2005-09-26 17:39:48 +00001044/* FIXME: It shouldn't be necessary to pass tlvsize here, TLVs can have
1045 * variable length (TE TLVs, sub TLVs). */
hasso92365882005-01-18 13:53:33 +00001046static void
jardineb5d44e2003-12-23 08:09:43 +00001047lsp_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to,
hassof390d2c2004-09-10 20:48:21 +00001048 int tlvsize, int frag_thold,
1049 int tlv_build_func (struct list *, struct stream *))
jardineb5d44e2003-12-23 08:09:43 +00001050{
1051 int count, i;
hassof390d2c2004-09-10 20:48:21 +00001052
jardineb5d44e2003-12-23 08:09:43 +00001053 /* can we fit all ? */
hassof390d2c2004-09-10 20:48:21 +00001054 if (!FRAG_NEEDED (lsp->pdu, frag_thold, listcount (*from) * tlvsize + 2))
1055 {
1056 tlv_build_func (*from, lsp->pdu);
Josh Bailey3f045a02012-03-24 08:35:20 -07001057 if (listcount (*to) != 0)
1058 {
1059 struct listnode *node, *nextnode;
1060 void *elem;
1061
1062 for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem))
1063 {
1064 listnode_add (*to, elem);
1065 list_delete_node (*from, node);
1066 }
1067 }
1068 else
1069 {
1070 list_free (*to);
1071 *to = *from;
1072 *from = NULL;
1073 }
jardineb5d44e2003-12-23 08:09:43 +00001074 }
hassof390d2c2004-09-10 20:48:21 +00001075 else if (!FRAG_NEEDED (lsp->pdu, frag_thold, tlvsize + 2))
1076 {
1077 /* fit all we can */
1078 count = FRAG_THOLD (lsp->pdu, frag_thold) - 2 -
1079 (STREAM_SIZE (lsp->pdu) - STREAM_REMAIN (lsp->pdu));
Josh Bailey3f045a02012-03-24 08:35:20 -07001080 count = count / tlvsize;
1081 if (count > (int)listcount (*from))
1082 count = listcount (*from);
hassof390d2c2004-09-10 20:48:21 +00001083 for (i = 0; i < count; i++)
1084 {
paul1eb8ef22005-04-07 07:30:20 +00001085 listnode_add (*to, listgetdata (listhead (*from)));
1086 listnode_delete (*from, listgetdata (listhead (*from)));
hassof390d2c2004-09-10 20:48:21 +00001087 }
1088 tlv_build_func (*to, lsp->pdu);
1089 }
paul9985f832005-02-09 15:51:56 +00001090 lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
jardineb5d44e2003-12-23 08:09:43 +00001091 return;
1092}
1093
Josh Bailey3f045a02012-03-24 08:35:20 -07001094static u_int16_t
1095lsp_rem_lifetime (struct isis_area *area, int level)
1096{
1097 u_int16_t rem_lifetime;
1098
1099 /* Add jitter to configured LSP lifetime */
1100 rem_lifetime = isis_jitter (area->max_lsp_lifetime[level - 1],
1101 MAX_AGE_JITTER);
1102
1103 /* No jitter if the max refresh will be less than configure gen interval */
Christian Franke9dfcca62015-11-10 18:32:11 +01001104 /* N.B. this calucation is acceptable since rem_lifetime is in [332,65535] at
1105 * this point */
Josh Bailey3f045a02012-03-24 08:35:20 -07001106 if (area->lsp_gen_interval[level - 1] > (rem_lifetime - 300))
1107 rem_lifetime = area->max_lsp_lifetime[level - 1];
1108
1109 return rem_lifetime;
1110}
1111
1112static u_int16_t
1113lsp_refresh_time (struct isis_lsp *lsp, u_int16_t rem_lifetime)
1114{
1115 struct isis_area *area = lsp->area;
1116 int level = lsp->level;
1117 u_int16_t refresh_time;
1118
1119 /* Add jitter to LSP refresh time */
1120 refresh_time = isis_jitter (area->lsp_refresh[level - 1],
1121 MAX_LSP_GEN_JITTER);
1122
1123 /* RFC 4444 : make sure the refresh time is at least less than 300
1124 * of the remaining lifetime and more than gen interval */
1125 if (refresh_time <= area->lsp_gen_interval[level - 1] ||
1126 refresh_time > (rem_lifetime - 300))
1127 refresh_time = rem_lifetime - 300;
1128
Christian Franke9dfcca62015-11-10 18:32:11 +01001129 /* In cornercases, refresh_time might be <= lsp_gen_interval, however
1130 * we accept this violation to satisfy refresh_time <= rem_lifetime - 300 */
Josh Bailey3f045a02012-03-24 08:35:20 -07001131
1132 return refresh_time;
1133}
1134
hasso92365882005-01-18 13:53:33 +00001135static struct isis_lsp *
hassof390d2c2004-09-10 20:48:21 +00001136lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0, struct isis_area *area,
1137 int level)
jardineb5d44e2003-12-23 08:09:43 +00001138{
1139 struct isis_lsp *lsp;
hassof390d2c2004-09-10 20:48:21 +00001140 u_char frag_id[ISIS_SYS_ID_LEN + 2];
1141
jardineb5d44e2003-12-23 08:09:43 +00001142 memcpy (frag_id, lsp0->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 1);
1143 LSP_FRAGMENT (frag_id) = frag_num;
Josh Bailey3f045a02012-03-24 08:35:20 -07001144 /* FIXME add authentication TLV for fragment LSPs */
jardineb5d44e2003-12-23 08:09:43 +00001145 lsp = lsp_search (frag_id, area->lspdb[level - 1]);
hassof390d2c2004-09-10 20:48:21 +00001146 if (lsp)
1147 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001148 /* Clear the TLVs */
hassof390d2c2004-09-10 20:48:21 +00001149 lsp_clear_data (lsp);
hassof390d2c2004-09-10 20:48:21 +00001150 return lsp;
jardineb5d44e2003-12-23 08:09:43 +00001151 }
Christian Frankef1fc1db2015-11-10 18:43:31 +01001152 lsp = lsp_new (area, frag_id, ntohs(lsp0->lsp_header->rem_lifetime), 0,
Amritha Nambiarc8ee9402015-08-24 16:40:14 -07001153 lsp_bits_generate (level, area->overload_bit,
1154 area->attached_bit), 0, level);
Josh Bailey3f045a02012-03-24 08:35:20 -07001155 lsp->area = area;
jardineb5d44e2003-12-23 08:09:43 +00001156 lsp->own_lsp = 1;
hassof390d2c2004-09-10 20:48:21 +00001157 lsp_insert (lsp, area->lspdb[level - 1]);
jardineb5d44e2003-12-23 08:09:43 +00001158 listnode_add (lsp0->lspu.frags, lsp);
1159 lsp->lspu.zero_lsp = lsp0;
jardineb5d44e2003-12-23 08:09:43 +00001160 return lsp;
1161}
1162
Christian Frankeacf98652015-11-12 14:24:22 +01001163static void
1164lsp_build_ext_reach_ipv4(struct isis_lsp *lsp, struct isis_area *area,
1165 struct tlvs *tlv_data)
1166{
1167 struct route_table *er_table;
1168 struct route_node *rn;
1169 struct prefix_ipv4 *ipv4;
1170 struct isis_ext_info *info;
1171 struct ipv4_reachability *ipreach;
1172 struct te_ipv4_reachability *te_ipreach;
1173
1174 er_table = get_ext_reach(area, AF_INET, lsp->level);
1175 if (!er_table)
1176 return;
1177
1178 for (rn = route_top(er_table); rn; rn = route_next(rn))
1179 {
1180 if (!rn->info)
1181 continue;
1182
1183 ipv4 = (struct prefix_ipv4*)&rn->p;
1184 info = rn->info;
1185 if (area->oldmetric)
1186 {
1187 if (tlv_data->ipv4_ext_reachs == NULL)
1188 {
1189 tlv_data->ipv4_ext_reachs = list_new();
1190 tlv_data->ipv4_ext_reachs->del = free_tlv;
1191 }
1192 ipreach = XMALLOC(MTYPE_ISIS_TLV, sizeof(*ipreach));
1193
1194 ipreach->prefix.s_addr = ipv4->prefix.s_addr;
1195 masklen2ip(ipv4->prefixlen, &ipreach->mask);
1196 ipreach->prefix.s_addr &= ipreach->mask.s_addr;
1197
1198 if ((info->metric & 0x3f) != info->metric)
1199 ipreach->metrics.metric_default = 0x3f;
1200 else
1201 ipreach->metrics.metric_default = info->metric;
1202 ipreach->metrics.metric_expense = METRICS_UNSUPPORTED;
1203 ipreach->metrics.metric_error = METRICS_UNSUPPORTED;
1204 ipreach->metrics.metric_delay = METRICS_UNSUPPORTED;
1205 listnode_add(tlv_data->ipv4_ext_reachs, ipreach);
1206 }
1207 if (area->newmetric)
1208 {
1209 if (tlv_data->te_ipv4_reachs == NULL)
1210 {
1211 tlv_data->te_ipv4_reachs = list_new();
1212 tlv_data->te_ipv4_reachs->del = free_tlv;
1213 }
1214 te_ipreach =
1215 XCALLOC(MTYPE_ISIS_TLV,
1216 sizeof(*te_ipreach) - 1 + PSIZE(ipv4->prefixlen));
1217 if (info->metric > MAX_WIDE_PATH_METRIC)
1218 te_ipreach->te_metric = htonl(MAX_WIDE_PATH_METRIC);
1219 else
1220 te_ipreach->te_metric = htonl(info->metric);
1221 te_ipreach->control = ipv4->prefixlen & 0x3f;
1222 memcpy(&te_ipreach->prefix_start, &ipv4->prefix.s_addr,
1223 PSIZE(ipv4->prefixlen));
1224 listnode_add(tlv_data->te_ipv4_reachs, te_ipreach);
1225 }
1226 }
1227}
1228
1229static void
1230lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, struct isis_area *area,
1231 struct tlvs *tlv_data)
1232{
1233 struct route_table *er_table;
1234 struct route_node *rn;
1235 struct prefix_ipv6 *ipv6;
1236 struct isis_ext_info *info;
1237 struct ipv6_reachability *ip6reach;
1238
1239 er_table = get_ext_reach(area, AF_INET6, lsp->level);
1240 if (!er_table)
1241 return;
1242
1243 for (rn = route_top(er_table); rn; rn = route_next(rn))
1244 {
1245 if (!rn->info)
1246 continue;
1247
1248 ipv6 = (struct prefix_ipv6*)&rn->p;
1249 info = rn->info;
1250
1251 if (tlv_data->ipv6_reachs == NULL)
1252 {
1253 tlv_data->ipv6_reachs = list_new();
1254 tlv_data->ipv6_reachs->del = free_tlv;
1255 }
1256 ip6reach = XCALLOC(MTYPE_ISIS_TLV, sizeof(*ip6reach));
1257 if (info->metric > MAX_WIDE_PATH_METRIC)
1258 ip6reach->metric = htonl(MAX_WIDE_PATH_METRIC);
1259 else
1260 ip6reach->metric = htonl(info->metric);
1261 ip6reach->control_info = DISTRIBUTION_EXTERNAL;
1262 ip6reach->prefix_len = ipv6->prefixlen;
1263 memcpy(ip6reach->prefix, ipv6->prefix.s6_addr, sizeof(ip6reach->prefix));
1264 listnode_add(tlv_data->ipv6_reachs, ip6reach);
1265 }
1266}
1267
1268static void
1269lsp_build_ext_reach (struct isis_lsp *lsp, struct isis_area *area,
1270 struct tlvs *tlv_data)
1271{
1272 lsp_build_ext_reach_ipv4(lsp, area, tlv_data);
1273 lsp_build_ext_reach_ipv6(lsp, area, tlv_data);
1274}
1275
jardineb5d44e2003-12-23 08:09:43 +00001276/*
1277 * Builds the LSP data part. This func creates a new frag whenever
1278 * area->lsp_frag_threshold is exceeded.
1279 */
hasso92365882005-01-18 13:53:33 +00001280static void
Josh Bailey3f045a02012-03-24 08:35:20 -07001281lsp_build (struct isis_lsp *lsp, struct isis_area *area)
jardineb5d44e2003-12-23 08:09:43 +00001282{
1283 struct is_neigh *is_neigh;
hassoaa4376e2005-09-26 17:39:48 +00001284 struct te_is_neigh *te_is_neigh;
hasso3fdb2dd2005-09-28 18:45:54 +00001285 struct listnode *node, *ipnode;
jardineb5d44e2003-12-23 08:09:43 +00001286 int level = lsp->level;
1287 struct isis_circuit *circuit;
1288 struct prefix_ipv4 *ipv4;
1289 struct ipv4_reachability *ipreach;
hassoaa4376e2005-09-26 17:39:48 +00001290 struct te_ipv4_reachability *te_ipreach;
jardineb5d44e2003-12-23 08:09:43 +00001291 struct isis_adjacency *nei;
1292#ifdef HAVE_IPV6
Christian Frankee28718a2015-11-10 18:33:14 +01001293 struct prefix_ipv6 *ipv6, ip6prefix;
jardineb5d44e2003-12-23 08:09:43 +00001294 struct ipv6_reachability *ip6reach;
1295#endif /* HAVE_IPV6 */
1296 struct tlvs tlv_data;
1297 struct isis_lsp *lsp0 = lsp;
hasso18a6dce2004-10-03 18:18:34 +00001298 struct in_addr *routerid;
Josh Bailey3f045a02012-03-24 08:35:20 -07001299 uint32_t expected = 0, found = 0;
1300 uint32_t metric;
1301 u_char zero_id[ISIS_SYS_ID_LEN + 1];
1302 int retval = ISIS_OK;
Christian Franke80a8f722015-11-12 14:21:47 +01001303 char buf[BUFSIZ];
1304
1305 lsp_debug("ISIS (%s): Constructing local system LSP for level %d", area->area_tag, level);
Josh Bailey3f045a02012-03-24 08:35:20 -07001306
1307 /*
1308 * Building the zero lsp
1309 */
1310 memset (zero_id, 0, ISIS_SYS_ID_LEN + 1);
1311
1312 /* Reset stream endp. Stream is always there and on every LSP refresh only
1313 * TLV part of it is overwritten. So we must seek past header we will not
1314 * touch. */
1315 stream_reset (lsp->pdu);
1316 stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
1317
1318 /*
1319 * Add the authentication info if its present
1320 */
1321 lsp_auth_add (lsp);
jardineb5d44e2003-12-23 08:09:43 +00001322
1323 /*
1324 * First add the tlvs related to area
1325 */
hassof390d2c2004-09-10 20:48:21 +00001326
jardineb5d44e2003-12-23 08:09:43 +00001327 /* Area addresses */
1328 if (lsp->tlv_data.area_addrs == NULL)
1329 lsp->tlv_data.area_addrs = list_new ();
1330 list_add_list (lsp->tlv_data.area_addrs, area->area_addrs);
Josh Bailey3f045a02012-03-24 08:35:20 -07001331 if (listcount (lsp->tlv_data.area_addrs) > 0)
1332 tlv_add_area_addrs (lsp->tlv_data.area_addrs, lsp->pdu);
1333
jardineb5d44e2003-12-23 08:09:43 +00001334 /* Protocols Supported */
hassof390d2c2004-09-10 20:48:21 +00001335 if (area->ip_circuits > 0
jardineb5d44e2003-12-23 08:09:43 +00001336#ifdef HAVE_IPV6
1337 || area->ipv6_circuits > 0
1338#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +00001339 )
jardineb5d44e2003-12-23 08:09:43 +00001340 {
hassoaac372f2005-09-01 17:52:33 +00001341 lsp->tlv_data.nlpids = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct nlpids));
jardineb5d44e2003-12-23 08:09:43 +00001342 lsp->tlv_data.nlpids->count = 0;
hassof390d2c2004-09-10 20:48:21 +00001343 if (area->ip_circuits > 0)
1344 {
Christian Franke80a8f722015-11-12 14:21:47 +01001345 lsp_debug("ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs", area->area_tag);
hassof390d2c2004-09-10 20:48:21 +00001346 lsp->tlv_data.nlpids->count++;
1347 lsp->tlv_data.nlpids->nlpids[0] = NLPID_IP;
1348 }
jardineb5d44e2003-12-23 08:09:43 +00001349#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +00001350 if (area->ipv6_circuits > 0)
1351 {
Christian Franke80a8f722015-11-12 14:21:47 +01001352 lsp_debug("ISIS (%s): Found IPv6 circuit, adding IPv6 to NLPIDs", area->area_tag);
hassof390d2c2004-09-10 20:48:21 +00001353 lsp->tlv_data.nlpids->count++;
1354 lsp->tlv_data.nlpids->nlpids[lsp->tlv_data.nlpids->count - 1] =
1355 NLPID_IPV6;
1356 }
jardineb5d44e2003-12-23 08:09:43 +00001357#endif /* HAVE_IPV6 */
Josh Bailey3f045a02012-03-24 08:35:20 -07001358 tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu);
jardineb5d44e2003-12-23 08:09:43 +00001359 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001360
jardineb5d44e2003-12-23 08:09:43 +00001361 /* Dynamic Hostname */
hassof390d2c2004-09-10 20:48:21 +00001362 if (area->dynhostname)
1363 {
Christian Frankef35169e2015-11-12 14:09:08 +01001364 const char *hostname = unix_hostname();
1365 size_t hostname_len = strlen(hostname);
1366
hassof390d2c2004-09-10 20:48:21 +00001367 lsp->tlv_data.hostname = XMALLOC (MTYPE_ISIS_TLV,
1368 sizeof (struct hostname));
jardin9e867fe2003-12-23 08:56:18 +00001369
Christian Frankef35169e2015-11-12 14:09:08 +01001370 strncpy((char *)lsp->tlv_data.hostname->name, hostname,
1371 sizeof(lsp->tlv_data.hostname->name));
1372 if (hostname_len <= MAX_TLV_LEN)
1373 lsp->tlv_data.hostname->namelen = hostname_len;
1374 else
1375 lsp->tlv_data.hostname->namelen = MAX_TLV_LEN;
1376
Christian Franke80a8f722015-11-12 14:21:47 +01001377 lsp_debug("ISIS (%s): Adding dynamic hostname '%.*s'", area->area_tag,
1378 lsp->tlv_data.hostname->namelen, lsp->tlv_data.hostname->name);
Josh Bailey3f045a02012-03-24 08:35:20 -07001379 tlv_add_dynamic_hostname (lsp->tlv_data.hostname, lsp->pdu);
hassof390d2c2004-09-10 20:48:21 +00001380 }
Christian Franke80a8f722015-11-12 14:21:47 +01001381 else
1382 {
1383 lsp_debug("ISIS (%s): Not adding dynamic hostname (disabled)", area->area_tag);
1384 }
jardineb5d44e2003-12-23 08:09:43 +00001385
hasso81ad8f62005-09-26 17:58:24 +00001386 /* IPv4 address and TE router ID TLVs. In case of the first one we don't
1387 * follow "C" vendor, but "J" vendor behavior - one IPv4 address is put into
1388 * LSP and this address is same as router id. */
Josh Bailey3f045a02012-03-24 08:35:20 -07001389 if (isis->router_id != 0)
hasso18a6dce2004-10-03 18:18:34 +00001390 {
Christian Franke80a8f722015-11-12 14:21:47 +01001391 inet_ntop(AF_INET, &isis->router_id, buf, sizeof(buf));
1392 lsp_debug("ISIS (%s): Adding router ID %s as IPv4 tlv.", area->area_tag, buf);
hasso18a6dce2004-10-03 18:18:34 +00001393 if (lsp->tlv_data.ipv4_addrs == NULL)
hassobe7d65d2005-09-02 01:38:16 +00001394 {
1395 lsp->tlv_data.ipv4_addrs = list_new ();
1396 lsp->tlv_data.ipv4_addrs->del = free_tlv;
1397 }
hasso18a6dce2004-10-03 18:18:34 +00001398
1399 routerid = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct in_addr));
Josh Bailey3f045a02012-03-24 08:35:20 -07001400 routerid->s_addr = isis->router_id;
hasso18a6dce2004-10-03 18:18:34 +00001401 listnode_add (lsp->tlv_data.ipv4_addrs, routerid);
hasso81ad8f62005-09-26 17:58:24 +00001402 tlv_add_in_addr (routerid, lsp->pdu, IPV4_ADDR);
hasso18a6dce2004-10-03 18:18:34 +00001403
hasso81ad8f62005-09-26 17:58:24 +00001404 /* Exactly same data is put into TE router ID TLV, but only if new style
1405 * TLV's are in use. */
1406 if (area->newmetric)
1407 {
Christian Franke80a8f722015-11-12 14:21:47 +01001408 lsp_debug("ISIS (%s): Adding router ID also as TE router ID tlv.", area->area_tag);
hasso81ad8f62005-09-26 17:58:24 +00001409 lsp->tlv_data.router_id = XMALLOC (MTYPE_ISIS_TLV,
1410 sizeof (struct in_addr));
Josh Bailey3f045a02012-03-24 08:35:20 -07001411 lsp->tlv_data.router_id->id.s_addr = isis->router_id;
1412 tlv_add_in_addr (&lsp->tlv_data.router_id->id, lsp->pdu,
1413 TE_ROUTER_ID);
hasso81ad8f62005-09-26 17:58:24 +00001414 }
hasso18a6dce2004-10-03 18:18:34 +00001415 }
Christian Franke80a8f722015-11-12 14:21:47 +01001416 else
1417 {
1418 lsp_debug("ISIS (%s): Router ID is unset. Not adding tlv.", area->area_tag);
1419 }
hassof1082d12005-09-19 04:23:34 +00001420
hasso81ad8f62005-09-26 17:58:24 +00001421 memset (&tlv_data, 0, sizeof (struct tlvs));
1422
hassof1082d12005-09-19 04:23:34 +00001423#ifdef TOPOLOGY_GENERATE
1424 /* If topology exists (and we create topology for level 1 only), create
1425 * (hardcoded) link to topology. */
Josh Bailey3f045a02012-03-24 08:35:20 -07001426 if (area->topology && level == IS_LEVEL_1)
hassof1082d12005-09-19 04:23:34 +00001427 {
1428 if (tlv_data.is_neighs == NULL)
hassoaa4376e2005-09-26 17:39:48 +00001429 {
1430 tlv_data.is_neighs = list_new ();
1431 tlv_data.is_neighs->del = free_tlv;
1432 }
hasso3fdb2dd2005-09-28 18:45:54 +00001433 is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
hassof1082d12005-09-19 04:23:34 +00001434
1435 memcpy (&is_neigh->neigh_id, area->topology_baseis, ISIS_SYS_ID_LEN);
1436 is_neigh->neigh_id[ISIS_SYS_ID_LEN - 1] = (1 & 0xFF);
1437 is_neigh->neigh_id[ISIS_SYS_ID_LEN - 2] = ((1 >> 8) & 0xFF);
1438 is_neigh->metrics.metric_default = 0x01;
1439 is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED;
1440 is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED;
1441 is_neigh->metrics.metric_error = METRICS_UNSUPPORTED;
1442 listnode_add (tlv_data.is_neighs, is_neigh);
1443 }
1444#endif /* TOPOLOGY_GENERATE */
1445
Christian Franke80a8f722015-11-12 14:21:47 +01001446 lsp_debug("ISIS (%s): Adding circuit specific information.", area->area_tag);
1447
hasso18a6dce2004-10-03 18:18:34 +00001448 /*
jardineb5d44e2003-12-23 08:09:43 +00001449 * Then build lists of tlvs related to circuits
1450 */
hasso3fdb2dd2005-09-28 18:45:54 +00001451 for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit))
hassof390d2c2004-09-10 20:48:21 +00001452 {
Christian Franke80a8f722015-11-12 14:21:47 +01001453 if (!circuit->interface)
1454 lsp_debug("ISIS (%s): Processing %s circuit %p with unknown interface",
1455 area->area_tag, circuit_type2string(circuit->circ_type), circuit);
1456 else
1457 lsp_debug("ISIS (%s): Processing %s circuit %s",
1458 area->area_tag, circuit_type2string(circuit->circ_type), circuit->interface->name);
1459
hassof390d2c2004-09-10 20:48:21 +00001460 if (circuit->state != C_STATE_UP)
Christian Franke80a8f722015-11-12 14:21:47 +01001461 {
1462 lsp_debug("ISIS (%s): Circuit is not up, ignoring.", area->area_tag);
1463 continue;
1464 }
jardineb5d44e2003-12-23 08:09:43 +00001465
hassof390d2c2004-09-10 20:48:21 +00001466 /*
1467 * Add IPv4 internal reachability of this circuit
1468 */
1469 if (circuit->ip_router && circuit->ip_addrs &&
1470 circuit->ip_addrs->count > 0)
1471 {
Christian Franke80a8f722015-11-12 14:21:47 +01001472 lsp_debug("ISIS (%s): Circuit has IPv4 active, adding respective TLVs.", area->area_tag);
hassoaa4376e2005-09-26 17:39:48 +00001473 if (area->oldmetric)
hassof390d2c2004-09-10 20:48:21 +00001474 {
hassoaa4376e2005-09-26 17:39:48 +00001475 if (tlv_data.ipv4_int_reachs == NULL)
1476 {
1477 tlv_data.ipv4_int_reachs = list_new ();
1478 tlv_data.ipv4_int_reachs->del = free_tlv;
1479 }
hasso3fdb2dd2005-09-28 18:45:54 +00001480 for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, ipnode, ipv4))
hassoaa4376e2005-09-26 17:39:48 +00001481 {
1482 ipreach =
1483 XMALLOC (MTYPE_ISIS_TLV, sizeof (struct ipv4_reachability));
1484 ipreach->metrics = circuit->metrics[level - 1];
1485 masklen2ip (ipv4->prefixlen, &ipreach->mask);
1486 ipreach->prefix.s_addr = ((ipreach->mask.s_addr) &
1487 (ipv4->prefix.s_addr));
Christian Franke80a8f722015-11-12 14:21:47 +01001488 inet_ntop(AF_INET, &ipreach->prefix.s_addr, buf, sizeof(buf));
1489 lsp_debug("ISIS (%s): Adding old-style IP reachability for %s/%d",
1490 area->area_tag, buf, ipv4->prefixlen);
hassoaa4376e2005-09-26 17:39:48 +00001491 listnode_add (tlv_data.ipv4_int_reachs, ipreach);
1492 }
hassof390d2c2004-09-10 20:48:21 +00001493 }
hassoaa4376e2005-09-26 17:39:48 +00001494 if (area->newmetric)
hassof390d2c2004-09-10 20:48:21 +00001495 {
hassoaa4376e2005-09-26 17:39:48 +00001496 if (tlv_data.te_ipv4_reachs == NULL)
1497 {
1498 tlv_data.te_ipv4_reachs = list_new ();
1499 tlv_data.te_ipv4_reachs->del = free_tlv;
1500 }
hasso3fdb2dd2005-09-28 18:45:54 +00001501 for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, ipnode, ipv4))
hassoaa4376e2005-09-26 17:39:48 +00001502 {
1503 /* FIXME All this assumes that we have no sub TLVs. */
1504 te_ipreach = XCALLOC (MTYPE_ISIS_TLV,
1505 sizeof (struct te_ipv4_reachability) +
1506 ((ipv4->prefixlen + 7)/8) - 1);
hasso309ddb12005-09-26 18:06:47 +00001507
1508 if (area->oldmetric)
1509 te_ipreach->te_metric = htonl (circuit->metrics[level - 1].metric_default);
1510 else
1511 te_ipreach->te_metric = htonl (circuit->te_metric[level - 1]);
1512
hassoaa4376e2005-09-26 17:39:48 +00001513 te_ipreach->control = (ipv4->prefixlen & 0x3F);
1514 memcpy (&te_ipreach->prefix_start, &ipv4->prefix.s_addr,
1515 (ipv4->prefixlen + 7)/8);
Christian Franke80a8f722015-11-12 14:21:47 +01001516 inet_ntop(AF_INET, &ipv4->prefix.s_addr, buf, sizeof(buf));
1517 lsp_debug("ISIS (%s): Adding te-style IP reachability for %s/%d",
1518 area->area_tag, buf, ipv4->prefixlen);
hassoaa4376e2005-09-26 17:39:48 +00001519 listnode_add (tlv_data.te_ipv4_reachs, te_ipreach);
1520 }
hassof390d2c2004-09-10 20:48:21 +00001521 }
hassof390d2c2004-09-10 20:48:21 +00001522 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001523
jardineb5d44e2003-12-23 08:09:43 +00001524#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +00001525 /*
1526 * Add IPv6 reachability of this circuit
1527 */
1528 if (circuit->ipv6_router && circuit->ipv6_non_link &&
1529 circuit->ipv6_non_link->count > 0)
1530 {
1531
1532 if (tlv_data.ipv6_reachs == NULL)
1533 {
1534 tlv_data.ipv6_reachs = list_new ();
hassobe7d65d2005-09-02 01:38:16 +00001535 tlv_data.ipv6_reachs->del = free_tlv;
hassof390d2c2004-09-10 20:48:21 +00001536 }
hasso3fdb2dd2005-09-28 18:45:54 +00001537 for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, ipnode, ipv6))
hassof390d2c2004-09-10 20:48:21 +00001538 {
hassof390d2c2004-09-10 20:48:21 +00001539 ip6reach =
hassoaac372f2005-09-01 17:52:33 +00001540 XCALLOC (MTYPE_ISIS_TLV, sizeof (struct ipv6_reachability));
hasso309ddb12005-09-26 18:06:47 +00001541
1542 if (area->oldmetric)
1543 ip6reach->metric =
1544 htonl (circuit->metrics[level - 1].metric_default);
1545 else
1546 ip6reach->metric = htonl (circuit->te_metric[level - 1]);
1547
hassof390d2c2004-09-10 20:48:21 +00001548 ip6reach->control_info = 0;
1549 ip6reach->prefix_len = ipv6->prefixlen;
Christian Frankee28718a2015-11-10 18:33:14 +01001550 memcpy(&ip6prefix, ipv6, sizeof(ip6prefix));
1551 apply_mask_ipv6(&ip6prefix);
Christian Franke80a8f722015-11-12 14:21:47 +01001552
Christian Frankee28718a2015-11-10 18:33:14 +01001553 inet_ntop(AF_INET6, &ip6prefix.prefix.s6_addr, buf, sizeof(buf));
Christian Franke80a8f722015-11-12 14:21:47 +01001554 lsp_debug("ISIS (%s): Adding IPv6 reachability for %s/%d",
1555 area->area_tag, buf, ipv6->prefixlen);
1556
Christian Frankee28718a2015-11-10 18:33:14 +01001557 memcpy (ip6reach->prefix, ip6prefix.prefix.s6_addr,
hasso67851572004-09-21 14:17:04 +00001558 sizeof (ip6reach->prefix));
hassof390d2c2004-09-10 20:48:21 +00001559 listnode_add (tlv_data.ipv6_reachs, ip6reach);
1560 }
1561 }
1562#endif /* HAVE_IPV6 */
1563
1564 switch (circuit->circ_type)
1565 {
1566 case CIRCUIT_T_BROADCAST:
Josh Bailey3f045a02012-03-24 08:35:20 -07001567 if (level & circuit->is_type)
hassof390d2c2004-09-10 20:48:21 +00001568 {
hassoaa4376e2005-09-26 17:39:48 +00001569 if (area->oldmetric)
hassof390d2c2004-09-10 20:48:21 +00001570 {
hassoaa4376e2005-09-26 17:39:48 +00001571 if (tlv_data.is_neighs == NULL)
1572 {
1573 tlv_data.is_neighs = list_new ();
1574 tlv_data.is_neighs->del = free_tlv;
1575 }
1576 is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
Josh Bailey3f045a02012-03-24 08:35:20 -07001577 if (level == IS_LEVEL_1)
hassoaa4376e2005-09-26 17:39:48 +00001578 memcpy (is_neigh->neigh_id,
1579 circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
1580 else
1581 memcpy (is_neigh->neigh_id,
1582 circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
1583 is_neigh->metrics = circuit->metrics[level - 1];
Josh Bailey3f045a02012-03-24 08:35:20 -07001584 if (!memcmp (is_neigh->neigh_id, zero_id,
1585 ISIS_SYS_ID_LEN + 1))
Christian Franke80a8f722015-11-12 14:21:47 +01001586 {
1587 XFREE (MTYPE_ISIS_TLV, is_neigh);
1588 lsp_debug("ISIS (%s): No DIS for circuit, not adding old-style IS neighbor.",
1589 area->area_tag);
1590 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001591 else
Christian Franke80a8f722015-11-12 14:21:47 +01001592 {
1593 listnode_add (tlv_data.is_neighs, is_neigh);
1594 lsp_debug("ISIS (%s): Adding DIS %s.%02x as old-style neighbor",
1595 area->area_tag, sysid_print(is_neigh->neigh_id),
1596 LSP_PSEUDO_ID(is_neigh->neigh_id));
1597 }
hassof390d2c2004-09-10 20:48:21 +00001598 }
hassoaa4376e2005-09-26 17:39:48 +00001599 if (area->newmetric)
1600 {
hassoaa4376e2005-09-26 17:39:48 +00001601 if (tlv_data.te_is_neighs == NULL)
1602 {
1603 tlv_data.te_is_neighs = list_new ();
1604 tlv_data.te_is_neighs->del = free_tlv;
1605 }
1606 te_is_neigh = XCALLOC (MTYPE_ISIS_TLV,
1607 sizeof (struct te_is_neigh));
Josh Bailey3f045a02012-03-24 08:35:20 -07001608 if (level == IS_LEVEL_1)
hassoaa4376e2005-09-26 17:39:48 +00001609 memcpy (te_is_neigh->neigh_id,
1610 circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
1611 else
1612 memcpy (te_is_neigh->neigh_id,
1613 circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
hasso309ddb12005-09-26 18:06:47 +00001614 if (area->oldmetric)
Josh Bailey3f045a02012-03-24 08:35:20 -07001615 metric = circuit->metrics[level - 1].metric_default;
hasso309ddb12005-09-26 18:06:47 +00001616 else
Josh Bailey3f045a02012-03-24 08:35:20 -07001617 metric = circuit->te_metric[level - 1];
1618 SET_TE_METRIC(te_is_neigh, metric);
1619 if (!memcmp (te_is_neigh->neigh_id, zero_id,
1620 ISIS_SYS_ID_LEN + 1))
Christian Franke80a8f722015-11-12 14:21:47 +01001621 {
1622 XFREE (MTYPE_ISIS_TLV, te_is_neigh);
1623 lsp_debug("ISIS (%s): No DIS for circuit, not adding te-style IS neighbor.",
1624 area->area_tag);
1625 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001626 else
Christian Franke80a8f722015-11-12 14:21:47 +01001627 {
1628 listnode_add (tlv_data.te_is_neighs, te_is_neigh);
1629 lsp_debug("ISIS (%s): Adding DIS %s.%02x as te-style neighbor",
1630 area->area_tag, sysid_print(te_is_neigh->neigh_id),
1631 LSP_PSEUDO_ID(te_is_neigh->neigh_id));
1632 }
hassoaa4376e2005-09-26 17:39:48 +00001633 }
hassof390d2c2004-09-10 20:48:21 +00001634 }
Christian Franke80a8f722015-11-12 14:21:47 +01001635 else
1636 {
1637 lsp_debug("ISIS (%s): Circuit is not active for current level. Not adding IS neighbors",
1638 area->area_tag);
1639 }
hassof390d2c2004-09-10 20:48:21 +00001640 break;
1641 case CIRCUIT_T_P2P:
1642 nei = circuit->u.p2p.neighbor;
1643 if (nei && (level & nei->circuit_t))
1644 {
hassoaa4376e2005-09-26 17:39:48 +00001645 if (area->oldmetric)
hassof390d2c2004-09-10 20:48:21 +00001646 {
hassoaa4376e2005-09-26 17:39:48 +00001647 if (tlv_data.is_neighs == NULL)
1648 {
1649 tlv_data.is_neighs = list_new ();
1650 tlv_data.is_neighs->del = free_tlv;
1651 }
1652 is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
1653 memcpy (is_neigh->neigh_id, nei->sysid, ISIS_SYS_ID_LEN);
1654 is_neigh->metrics = circuit->metrics[level - 1];
1655 listnode_add (tlv_data.is_neighs, is_neigh);
Christian Franke80a8f722015-11-12 14:21:47 +01001656 lsp_debug("ISIS (%s): Adding old-style is reach for %s", area->area_tag,
1657 sysid_print(is_neigh->neigh_id));
hassof390d2c2004-09-10 20:48:21 +00001658 }
hassoaa4376e2005-09-26 17:39:48 +00001659 if (area->newmetric)
1660 {
1661 uint32_t metric;
1662
1663 if (tlv_data.te_is_neighs == NULL)
1664 {
1665 tlv_data.te_is_neighs = list_new ();
1666 tlv_data.te_is_neighs->del = free_tlv;
1667 }
1668 te_is_neigh = XCALLOC (MTYPE_ISIS_TLV,
1669 sizeof (struct te_is_neigh));
1670 memcpy (te_is_neigh->neigh_id, nei->sysid, ISIS_SYS_ID_LEN);
Josh Bailey3f045a02012-03-24 08:35:20 -07001671 metric = circuit->te_metric[level - 1];
1672 SET_TE_METRIC(te_is_neigh, metric);
hassoaa4376e2005-09-26 17:39:48 +00001673 listnode_add (tlv_data.te_is_neighs, te_is_neigh);
Christian Franke80a8f722015-11-12 14:21:47 +01001674 lsp_debug("ISIS (%s): Adding te-style is reach for %s", area->area_tag,
1675 sysid_print(te_is_neigh->neigh_id));
hassoaa4376e2005-09-26 17:39:48 +00001676 }
hassof390d2c2004-09-10 20:48:21 +00001677 }
Christian Franke80a8f722015-11-12 14:21:47 +01001678 else
1679 {
1680 lsp_debug("ISIS (%s): No adjacency for given level on this circuit. Not adding IS neighbors",
1681 area->area_tag);
1682 }
hassof390d2c2004-09-10 20:48:21 +00001683 break;
Josh Bailey3f045a02012-03-24 08:35:20 -07001684 case CIRCUIT_T_LOOPBACK:
1685 break;
hassof390d2c2004-09-10 20:48:21 +00001686 default:
1687 zlog_warn ("lsp_area_create: unknown circuit type");
1688 }
1689 }
1690
Christian Frankeacf98652015-11-12 14:24:22 +01001691 lsp_build_ext_reach(lsp, area, &tlv_data);
1692
Christian Franke80a8f722015-11-12 14:21:47 +01001693 lsp_debug("ISIS (%s): LSP construction is complete. Serializing...", area->area_tag);
1694
hassof390d2c2004-09-10 20:48:21 +00001695 while (tlv_data.ipv4_int_reachs && listcount (tlv_data.ipv4_int_reachs))
1696 {
1697 if (lsp->tlv_data.ipv4_int_reachs == NULL)
1698 lsp->tlv_data.ipv4_int_reachs = list_new ();
1699 lsp_tlv_fit (lsp, &tlv_data.ipv4_int_reachs,
1700 &lsp->tlv_data.ipv4_int_reachs,
1701 IPV4_REACH_LEN, area->lsp_frag_threshold,
Christian Frankeacf98652015-11-12 14:24:22 +01001702 tlv_add_ipv4_int_reachs);
hassof390d2c2004-09-10 20:48:21 +00001703 if (tlv_data.ipv4_int_reachs && listcount (tlv_data.ipv4_int_reachs))
1704 lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
1705 lsp0, area, level);
1706 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001707
Christian Frankeacf98652015-11-12 14:24:22 +01001708 while (tlv_data.ipv4_ext_reachs && listcount (tlv_data.ipv4_ext_reachs))
1709 {
1710 if (lsp->tlv_data.ipv4_ext_reachs == NULL)
1711 lsp->tlv_data.ipv4_ext_reachs = list_new ();
1712 lsp_tlv_fit (lsp, &tlv_data.ipv4_ext_reachs,
1713 &lsp->tlv_data.ipv4_ext_reachs,
1714 IPV4_REACH_LEN, area->lsp_frag_threshold,
1715 tlv_add_ipv4_ext_reachs);
1716 if (tlv_data.ipv4_ext_reachs && listcount (tlv_data.ipv4_ext_reachs))
1717 lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
1718 lsp0, area, level);
1719 }
1720
hassoaa4376e2005-09-26 17:39:48 +00001721 /* FIXME: We pass maximum te_ipv4_reachability length to the lsp_tlv_fit()
1722 * for now. lsp_tlv_fit() needs to be fixed to deal with variable length
1723 * TLVs (sub TLVs!). */
1724 while (tlv_data.te_ipv4_reachs && listcount (tlv_data.te_ipv4_reachs))
1725 {
1726 if (lsp->tlv_data.te_ipv4_reachs == NULL)
1727 lsp->tlv_data.te_ipv4_reachs = list_new ();
1728 lsp_tlv_fit (lsp, &tlv_data.te_ipv4_reachs,
1729 &lsp->tlv_data.te_ipv4_reachs,
Josh Bailey3f045a02012-03-24 08:35:20 -07001730 TE_IPV4_REACH_LEN, area->lsp_frag_threshold,
1731 tlv_add_te_ipv4_reachs);
hassoaa4376e2005-09-26 17:39:48 +00001732 if (tlv_data.te_ipv4_reachs && listcount (tlv_data.te_ipv4_reachs))
1733 lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
1734 lsp0, area, level);
1735 }
hassof390d2c2004-09-10 20:48:21 +00001736
1737#ifdef HAVE_IPV6
1738 while (tlv_data.ipv6_reachs && listcount (tlv_data.ipv6_reachs))
1739 {
1740 if (lsp->tlv_data.ipv6_reachs == NULL)
1741 lsp->tlv_data.ipv6_reachs = list_new ();
1742 lsp_tlv_fit (lsp, &tlv_data.ipv6_reachs,
1743 &lsp->tlv_data.ipv6_reachs,
1744 IPV6_REACH_LEN, area->lsp_frag_threshold,
1745 tlv_add_ipv6_reachs);
1746 if (tlv_data.ipv6_reachs && listcount (tlv_data.ipv6_reachs))
1747 lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
1748 lsp0, area, level);
jardineb5d44e2003-12-23 08:09:43 +00001749 }
1750#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +00001751
1752 while (tlv_data.is_neighs && listcount (tlv_data.is_neighs))
1753 {
1754 if (lsp->tlv_data.is_neighs == NULL)
1755 lsp->tlv_data.is_neighs = list_new ();
1756 lsp_tlv_fit (lsp, &tlv_data.is_neighs,
1757 &lsp->tlv_data.is_neighs,
1758 IS_NEIGHBOURS_LEN, area->lsp_frag_threshold,
1759 tlv_add_is_neighs);
1760 if (tlv_data.is_neighs && listcount (tlv_data.is_neighs))
1761 lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
1762 lsp0, area, level);
jardineb5d44e2003-12-23 08:09:43 +00001763 }
jardineb5d44e2003-12-23 08:09:43 +00001764
hassoaa4376e2005-09-26 17:39:48 +00001765 while (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs))
1766 {
1767 if (lsp->tlv_data.te_is_neighs == NULL)
1768 lsp->tlv_data.te_is_neighs = list_new ();
1769 lsp_tlv_fit (lsp, &tlv_data.te_is_neighs, &lsp->tlv_data.te_is_neighs,
1770 IS_NEIGHBOURS_LEN, area->lsp_frag_threshold,
1771 tlv_add_te_is_neighs);
1772 if (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs))
1773 lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
1774 lsp0, area, level);
1775 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001776 lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
hassoaa4376e2005-09-26 17:39:48 +00001777
1778 free_tlvs (&tlv_data);
Josh Bailey3f045a02012-03-24 08:35:20 -07001779
1780 /* Validate the LSP */
1781 retval = parse_tlvs (area->area_tag, STREAM_DATA (lsp->pdu) +
1782 ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN,
1783 stream_get_endp (lsp->pdu) -
1784 ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN,
1785 &expected, &found, &tlv_data, NULL);
1786 assert (retval == ISIS_OK);
1787
jardineb5d44e2003-12-23 08:09:43 +00001788 return;
1789}
jardineb5d44e2003-12-23 08:09:43 +00001790
1791/*
Josh Bailey3f045a02012-03-24 08:35:20 -07001792 * 7.3.7 and 7.3.9 Generation on non-pseudonode LSPs
jardineb5d44e2003-12-23 08:09:43 +00001793 */
Josh Bailey3f045a02012-03-24 08:35:20 -07001794int
1795lsp_generate (struct isis_area *area, int level)
hassof390d2c2004-09-10 20:48:21 +00001796{
jardineb5d44e2003-12-23 08:09:43 +00001797 struct isis_lsp *oldlsp, *newlsp;
1798 u_int32_t seq_num = 0;
1799 u_char lspid[ISIS_SYS_ID_LEN + 2];
Josh Bailey3f045a02012-03-24 08:35:20 -07001800 u_int16_t rem_lifetime, refresh_time;
1801
1802 if ((area == NULL) || (area->is_type & level) != level)
1803 return ISIS_ERROR;
jardineb5d44e2003-12-23 08:09:43 +00001804
1805 memset (&lspid, 0, ISIS_SYS_ID_LEN + 2);
1806 memcpy (&lspid, isis->sysid, ISIS_SYS_ID_LEN);
1807
1808 /* only builds the lsp if the area shares the level */
Josh Bailey3f045a02012-03-24 08:35:20 -07001809 oldlsp = lsp_search (lspid, area->lspdb[level - 1]);
1810 if (oldlsp)
hassof390d2c2004-09-10 20:48:21 +00001811 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001812 /* FIXME: we should actually initiate a purge */
1813 seq_num = ntohl (oldlsp->lsp_header->seq_num);
1814 lsp_search_and_destroy (oldlsp->lsp_header->lsp_id,
1815 area->lspdb[level - 1]);
hassof390d2c2004-09-10 20:48:21 +00001816 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001817 rem_lifetime = lsp_rem_lifetime (area, level);
Christian Frankef1fc1db2015-11-10 18:43:31 +01001818 newlsp = lsp_new (area, lspid, rem_lifetime, seq_num,
Amritha Nambiarc8ee9402015-08-24 16:40:14 -07001819 area->is_type | area->overload_bit | area->attached_bit,
1820 0, level);
Josh Bailey3f045a02012-03-24 08:35:20 -07001821 newlsp->area = area;
1822 newlsp->own_lsp = 1;
jardineb5d44e2003-12-23 08:09:43 +00001823
Josh Bailey3f045a02012-03-24 08:35:20 -07001824 lsp_insert (newlsp, area->lspdb[level - 1]);
1825 /* build_lsp_data (newlsp, area); */
1826 lsp_build (newlsp, area);
1827 /* time to calculate our checksum */
1828 lsp_seqnum_update (newlsp);
Christian Franke61010c32015-11-10 18:43:34 +01001829 newlsp->last_generated = time(NULL);
Josh Bailey3f045a02012-03-24 08:35:20 -07001830 lsp_set_all_srmflags (newlsp);
1831
1832 refresh_time = lsp_refresh_time (newlsp, rem_lifetime);
Christian Franke61010c32015-11-10 18:43:34 +01001833
Josh Bailey3f045a02012-03-24 08:35:20 -07001834 THREAD_TIMER_OFF (area->t_lsp_refresh[level - 1]);
Christian Franke61010c32015-11-10 18:43:34 +01001835 area->lsp_regenerate_pending[level - 1] = 0;
Josh Bailey3f045a02012-03-24 08:35:20 -07001836 if (level == IS_LEVEL_1)
1837 THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
1838 lsp_l1_refresh, area, refresh_time);
1839 else if (level == IS_LEVEL_2)
1840 THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
1841 lsp_l2_refresh, area, refresh_time);
1842
1843 if (isis->debugs & DEBUG_UPDATE_PACKETS)
hassof390d2c2004-09-10 20:48:21 +00001844 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001845 zlog_debug ("ISIS-Upd (%s): Building L%d LSP %s, len %d, "
1846 "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us",
1847 area->area_tag, level,
1848 rawlspid_print (newlsp->lsp_header->lsp_id),
1849 ntohl (newlsp->lsp_header->pdu_len),
1850 ntohl (newlsp->lsp_header->seq_num),
1851 ntohs (newlsp->lsp_header->checksum),
1852 ntohs (newlsp->lsp_header->rem_lifetime),
1853 refresh_time);
hassof390d2c2004-09-10 20:48:21 +00001854 }
Christian Franke61010c32015-11-10 18:43:34 +01001855 sched_debug("ISIS (%s): Built L%d LSP. Set triggered regenerate to non-pending.",
1856 area->area_tag, level);
jardineb5d44e2003-12-23 08:09:43 +00001857
1858 return ISIS_OK;
1859}
1860
1861/*
Josh Bailey3f045a02012-03-24 08:35:20 -07001862 * Search own LSPs, update holding time and set SRM
jardineb5d44e2003-12-23 08:09:43 +00001863 */
hasso92365882005-01-18 13:53:33 +00001864static int
Josh Bailey3f045a02012-03-24 08:35:20 -07001865lsp_regenerate (struct isis_area *area, int level)
jardineb5d44e2003-12-23 08:09:43 +00001866{
David Lampartere8aca322012-11-27 01:10:30 +00001867 dict_t *lspdb;
jardineb5d44e2003-12-23 08:09:43 +00001868 struct isis_lsp *lsp, *frag;
1869 struct listnode *node;
1870 u_char lspid[ISIS_SYS_ID_LEN + 2];
Josh Bailey3f045a02012-03-24 08:35:20 -07001871 u_int16_t rem_lifetime, refresh_time;
1872
1873 if ((area == NULL) || (area->is_type & level) != level)
1874 return ISIS_ERROR;
jardineb5d44e2003-12-23 08:09:43 +00001875
David Lampartere8aca322012-11-27 01:10:30 +00001876 lspdb = area->lspdb[level - 1];
1877
jardineb5d44e2003-12-23 08:09:43 +00001878 memset (lspid, 0, ISIS_SYS_ID_LEN + 2);
1879 memcpy (lspid, isis->sysid, ISIS_SYS_ID_LEN);
hassof390d2c2004-09-10 20:48:21 +00001880
jardineb5d44e2003-12-23 08:09:43 +00001881 lsp = lsp_search (lspid, lspdb);
jardineb5d44e2003-12-23 08:09:43 +00001882
hassof390d2c2004-09-10 20:48:21 +00001883 if (!lsp)
1884 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001885 zlog_err ("ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!",
1886 area->area_tag, level);
hassof390d2c2004-09-10 20:48:21 +00001887 return ISIS_ERROR;
1888 }
1889
1890 lsp_clear_data (lsp);
Josh Bailey3f045a02012-03-24 08:35:20 -07001891 lsp_build (lsp, area);
Amritha Nambiarc8ee9402015-08-24 16:40:14 -07001892 lsp->lsp_header->lsp_bits = lsp_bits_generate (level, area->overload_bit,
1893 area->attached_bit);
Josh Bailey3f045a02012-03-24 08:35:20 -07001894 rem_lifetime = lsp_rem_lifetime (area, level);
1895 lsp->lsp_header->rem_lifetime = htons (rem_lifetime);
jardineb5d44e2003-12-23 08:09:43 +00001896 lsp_seqnum_update (lsp);
hassof390d2c2004-09-10 20:48:21 +00001897
Josh Bailey3f045a02012-03-24 08:35:20 -07001898 lsp->last_generated = time (NULL);
1899 lsp_set_all_srmflags (lsp);
1900 for (ALL_LIST_ELEMENTS_RO (lsp->lspu.frags, node, frag))
1901 {
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001902 frag->lsp_header->lsp_bits = lsp_bits_generate (level,
Amritha Nambiarc8ee9402015-08-24 16:40:14 -07001903 area->overload_bit,
1904 area->attached_bit);
Josh Bailey3f045a02012-03-24 08:35:20 -07001905 /* Set the lifetime values of all the fragments to the same value,
1906 * so that no fragment expires before the lsp is refreshed.
1907 */
1908 frag->lsp_header->rem_lifetime = htons (rem_lifetime);
1909 lsp_set_all_srmflags (frag);
1910 }
1911
1912 refresh_time = lsp_refresh_time (lsp, rem_lifetime);
1913 if (level == IS_LEVEL_1)
1914 THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
1915 lsp_l1_refresh, area, refresh_time);
1916 else if (level == IS_LEVEL_2)
1917 THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
1918 lsp_l2_refresh, area, refresh_time);
Christian Franke61010c32015-11-10 18:43:34 +01001919 area->lsp_regenerate_pending[level - 1] = 0;
Josh Bailey3f045a02012-03-24 08:35:20 -07001920
hassof390d2c2004-09-10 20:48:21 +00001921 if (isis->debugs & DEBUG_UPDATE_PACKETS)
1922 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001923 zlog_debug ("ISIS-Upd (%s): Refreshing our L%d LSP %s, len %d, "
1924 "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us",
1925 area->area_tag, level,
1926 rawlspid_print (lsp->lsp_header->lsp_id),
1927 ntohl (lsp->lsp_header->pdu_len),
1928 ntohl (lsp->lsp_header->seq_num),
1929 ntohs (lsp->lsp_header->checksum),
1930 ntohs (lsp->lsp_header->rem_lifetime),
1931 refresh_time);
hassof390d2c2004-09-10 20:48:21 +00001932 }
Christian Franke61010c32015-11-10 18:43:34 +01001933 sched_debug("ISIS (%s): Rebuilt L%d LSP. Set triggered regenerate to non-pending.",
1934 area->area_tag, level);
jardineb5d44e2003-12-23 08:09:43 +00001935
jardineb5d44e2003-12-23 08:09:43 +00001936 return ISIS_OK;
1937}
1938
jardineb5d44e2003-12-23 08:09:43 +00001939/*
Josh Bailey3f045a02012-03-24 08:35:20 -07001940 * Something has changed or periodic refresh -> regenerate LSP
jardineb5d44e2003-12-23 08:09:43 +00001941 */
Josh Bailey3f045a02012-03-24 08:35:20 -07001942static int
1943lsp_l1_refresh (struct thread *thread)
jardineb5d44e2003-12-23 08:09:43 +00001944{
1945 struct isis_area *area;
jardineb5d44e2003-12-23 08:09:43 +00001946
1947 area = THREAD_ARG (thread);
1948 assert (area);
hassof390d2c2004-09-10 20:48:21 +00001949
jardineb5d44e2003-12-23 08:09:43 +00001950 area->t_lsp_refresh[0] = NULL;
Josh Bailey3f045a02012-03-24 08:35:20 -07001951 area->lsp_regenerate_pending[0] = 0;
hassof390d2c2004-09-10 20:48:21 +00001952
Josh Bailey3f045a02012-03-24 08:35:20 -07001953 if ((area->is_type & IS_LEVEL_1) == 0)
1954 return ISIS_ERROR;
jardineb5d44e2003-12-23 08:09:43 +00001955
Christian Franke61010c32015-11-10 18:43:34 +01001956 sched_debug("ISIS (%s): LSP L1 refresh timer expired. Refreshing LSP...", area->area_tag);
Josh Bailey3f045a02012-03-24 08:35:20 -07001957 return lsp_regenerate (area, IS_LEVEL_1);
jardineb5d44e2003-12-23 08:09:43 +00001958}
1959
Josh Bailey3f045a02012-03-24 08:35:20 -07001960static int
1961lsp_l2_refresh (struct thread *thread)
jardineb5d44e2003-12-23 08:09:43 +00001962{
1963 struct isis_area *area;
jardineb5d44e2003-12-23 08:09:43 +00001964
1965 area = THREAD_ARG (thread);
1966 assert (area);
hassof390d2c2004-09-10 20:48:21 +00001967
jardineb5d44e2003-12-23 08:09:43 +00001968 area->t_lsp_refresh[1] = NULL;
jardineb5d44e2003-12-23 08:09:43 +00001969 area->lsp_regenerate_pending[1] = 0;
hassof390d2c2004-09-10 20:48:21 +00001970
Josh Bailey3f045a02012-03-24 08:35:20 -07001971 if ((area->is_type & IS_LEVEL_2) == 0)
1972 return ISIS_ERROR;
1973
Christian Franke61010c32015-11-10 18:43:34 +01001974 sched_debug("ISIS (%s): LSP L2 refresh timer expired. Refreshing LSP...", area->area_tag);
Josh Bailey3f045a02012-03-24 08:35:20 -07001975 return lsp_regenerate (area, IS_LEVEL_2);
jardineb5d44e2003-12-23 08:09:43 +00001976}
1977
hassof390d2c2004-09-10 20:48:21 +00001978int
Josh Bailey3f045a02012-03-24 08:35:20 -07001979lsp_regenerate_schedule (struct isis_area *area, int level, int all_pseudo)
jardineb5d44e2003-12-23 08:09:43 +00001980{
1981 struct isis_lsp *lsp;
1982 u_char id[ISIS_SYS_ID_LEN + 2];
1983 time_t now, diff;
Christian Franke61010c32015-11-10 18:43:34 +01001984 long timeout;
Josh Bailey3f045a02012-03-24 08:35:20 -07001985 struct listnode *cnode;
1986 struct isis_circuit *circuit;
1987 int lvl;
1988
1989 if (area == NULL)
1990 return ISIS_ERROR;
1991
Christian Franke61010c32015-11-10 18:43:34 +01001992 sched_debug("ISIS (%s): Scheduling regeneration of %s LSPs, %sincluding PSNs",
1993 area->area_tag, circuit_t2string(level), all_pseudo ? "" : "not ");
1994
hassof390d2c2004-09-10 20:48:21 +00001995 memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
1996 LSP_PSEUDO_ID (id) = LSP_FRAGMENT (id) = 0;
jardineb5d44e2003-12-23 08:09:43 +00001997 now = time (NULL);
Josh Bailey3f045a02012-03-24 08:35:20 -07001998
1999 for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++)
hassof390d2c2004-09-10 20:48:21 +00002000 {
Josh Bailey3f045a02012-03-24 08:35:20 -07002001 if (!((level & lvl) && (area->is_type & lvl)))
2002 continue;
2003
Christian Franke61010c32015-11-10 18:43:34 +01002004 sched_debug("ISIS (%s): Checking whether L%d needs to be scheduled",
2005 area->area_tag, lvl);
2006
Josh Bailey3f045a02012-03-24 08:35:20 -07002007 if (area->lsp_regenerate_pending[lvl - 1])
Christian Franke61010c32015-11-10 18:43:34 +01002008 {
2009 struct timeval remain = thread_timer_remain(area->t_lsp_refresh[lvl - 1]);
2010 sched_debug("ISIS (%s): Regeneration is already pending, nothing todo."
2011 " (Due in %lld.%03lld seconds)", area->area_tag,
2012 (long long)remain.tv_sec, (long long)remain.tv_usec / 1000);
2013 continue;
2014 }
Josh Bailey3f045a02012-03-24 08:35:20 -07002015
2016 lsp = lsp_search (id, area->lspdb[lvl - 1]);
2017 if (!lsp)
Christian Franke61010c32015-11-10 18:43:34 +01002018 {
2019 sched_debug("ISIS (%s): We do not have any LSPs to regenerate, nothing todo.",
2020 area->area_tag);
2021 continue;
2022 }
Josh Bailey3f045a02012-03-24 08:35:20 -07002023
hassof390d2c2004-09-10 20:48:21 +00002024 /*
2025 * Throttle avoidance
2026 */
Christian Franke61010c32015-11-10 18:43:34 +01002027 sched_debug("ISIS (%s): Will schedule regen timer. Last run was: %lld, Now is: %lld",
2028 area->area_tag, (long long)lsp->last_generated, (long long)now);
Josh Bailey3f045a02012-03-24 08:35:20 -07002029 THREAD_TIMER_OFF (area->t_lsp_refresh[lvl - 1]);
hassof390d2c2004-09-10 20:48:21 +00002030 diff = now - lsp->last_generated;
Josh Bailey3f045a02012-03-24 08:35:20 -07002031 if (diff < area->lsp_gen_interval[lvl - 1])
2032 {
Christian Franke61010c32015-11-10 18:43:34 +01002033 timeout = 1000 * (area->lsp_gen_interval[lvl - 1] - diff);
2034 sched_debug("ISIS (%s): Scheduling in %ld ms to match configured lsp_gen_interval",
2035 area->area_tag, timeout);
Josh Bailey3f045a02012-03-24 08:35:20 -07002036 }
hassof390d2c2004-09-10 20:48:21 +00002037 else
Josh Bailey3f045a02012-03-24 08:35:20 -07002038 {
Michael Zinggbe62b172012-10-26 11:18:19 +02002039 /*
2040 * lsps are not regenerated if lsp_regenerate function is called
2041 * directly. However if the lsp_regenerate call is queued for
2042 * later execution it works.
2043 */
Christian Franke61010c32015-11-10 18:43:34 +01002044 timeout = 100;
2045 sched_debug("ISIS (%s): Last generation was more than lsp_gen_interval ago."
2046 " Scheduling for execution in %ld ms.", area->area_tag, timeout);
2047 }
2048
2049 area->lsp_regenerate_pending[lvl - 1] = 1;
2050 if (lvl == IS_LEVEL_1)
2051 {
2052 THREAD_TIMER_MSEC_ON(master, area->t_lsp_refresh[lvl - 1],
2053 lsp_l1_refresh, area, timeout);
2054 }
2055 else if (lvl == IS_LEVEL_2)
2056 {
2057 THREAD_TIMER_MSEC_ON(master, area->t_lsp_refresh[lvl - 1],
2058 lsp_l2_refresh, area, timeout);
Josh Bailey3f045a02012-03-24 08:35:20 -07002059 }
hassof390d2c2004-09-10 20:48:21 +00002060 }
Josh Bailey3f045a02012-03-24 08:35:20 -07002061
2062 if (all_pseudo)
hassof390d2c2004-09-10 20:48:21 +00002063 {
Josh Bailey3f045a02012-03-24 08:35:20 -07002064 for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit))
2065 lsp_regenerate_schedule_pseudo (circuit, level);
hassof390d2c2004-09-10 20:48:21 +00002066 }
2067
2068 return ISIS_OK;
jardineb5d44e2003-12-23 08:09:43 +00002069}
2070
2071/*
2072 * Funcs for pseudonode LSPs
2073 */
2074
2075/*
2076 * 7.3.8 and 7.3.10 Generation of level 1 and 2 pseudonode LSPs
2077 */
hasso92365882005-01-18 13:53:33 +00002078static void
hassof390d2c2004-09-10 20:48:21 +00002079lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit,
2080 int level)
jardineb5d44e2003-12-23 08:09:43 +00002081{
2082 struct isis_adjacency *adj;
2083 struct is_neigh *is_neigh;
hassoaa4376e2005-09-26 17:39:48 +00002084 struct te_is_neigh *te_is_neigh;
jardineb5d44e2003-12-23 08:09:43 +00002085 struct es_neigh *es_neigh;
2086 struct list *adj_list;
hasso3fdb2dd2005-09-28 18:45:54 +00002087 struct listnode *node;
Christian Franke80a8f722015-11-12 14:21:47 +01002088 struct isis_area *area = circuit->area;
2089
2090 lsp_debug("ISIS (%s): Constructing pseudo LSP %s for interface %s level %d",
2091 area->area_tag, rawlspid_print(lsp->lsp_header->lsp_id),
2092 circuit->interface->name, level);
hassof390d2c2004-09-10 20:48:21 +00002093
jardineb5d44e2003-12-23 08:09:43 +00002094 lsp->level = level;
Josh Bailey3f045a02012-03-24 08:35:20 -07002095 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
Amritha Nambiarc8ee9402015-08-24 16:40:14 -07002096 lsp->lsp_header->lsp_bits = lsp_bits_generate (level, 0,
2097 circuit->area->attached_bit);
jardineb5d44e2003-12-23 08:09:43 +00002098
2099 /*
2100 * add self to IS neighbours
2101 */
hassoaa4376e2005-09-26 17:39:48 +00002102 if (circuit->area->oldmetric)
hassof390d2c2004-09-10 20:48:21 +00002103 {
hassoaa4376e2005-09-26 17:39:48 +00002104 if (lsp->tlv_data.is_neighs == NULL)
2105 {
2106 lsp->tlv_data.is_neighs = list_new ();
2107 lsp->tlv_data.is_neighs->del = free_tlv;
2108 }
2109 is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
paul15935e92005-05-03 09:27:23 +00002110
hassoaa4376e2005-09-26 17:39:48 +00002111 memcpy (&is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN);
2112 listnode_add (lsp->tlv_data.is_neighs, is_neigh);
Christian Franke80a8f722015-11-12 14:21:47 +01002113 lsp_debug("ISIS (%s): Adding %s.%02x as old-style neighbor (self)",
2114 area->area_tag, sysid_print(is_neigh->neigh_id),
2115 LSP_PSEUDO_ID(is_neigh->neigh_id));
hassoaa4376e2005-09-26 17:39:48 +00002116 }
2117 if (circuit->area->newmetric)
2118 {
2119 if (lsp->tlv_data.te_is_neighs == NULL)
2120 {
2121 lsp->tlv_data.te_is_neighs = list_new ();
2122 lsp->tlv_data.te_is_neighs->del = free_tlv;
2123 }
2124 te_is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct te_is_neigh));
2125
2126 memcpy (&te_is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN);
2127 listnode_add (lsp->tlv_data.te_is_neighs, te_is_neigh);
Christian Franke80a8f722015-11-12 14:21:47 +01002128 lsp_debug("ISIS (%s): Adding %s.%02x as te-style neighbor (self)",
2129 area->area_tag, sysid_print(te_is_neigh->neigh_id),
2130 LSP_PSEUDO_ID(te_is_neigh->neigh_id));
hassoaa4376e2005-09-26 17:39:48 +00002131 }
hassof390d2c2004-09-10 20:48:21 +00002132
2133 adj_list = list_new ();
2134 isis_adj_build_up_list (circuit->u.bc.adjdb[level - 1], adj_list);
2135
hasso3fdb2dd2005-09-28 18:45:54 +00002136 for (ALL_LIST_ELEMENTS_RO (adj_list, node, adj))
hassof390d2c2004-09-10 20:48:21 +00002137 {
Josh Bailey3f045a02012-03-24 08:35:20 -07002138 if (adj->level & level)
hassof390d2c2004-09-10 20:48:21 +00002139 {
Josh Bailey3f045a02012-03-24 08:35:20 -07002140 if ((level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_L1_IS) ||
2141 (level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_L2_IS &&
hassoaa4376e2005-09-26 17:39:48 +00002142 adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||
Josh Bailey3f045a02012-03-24 08:35:20 -07002143 (level == IS_LEVEL_2 && adj->sys_type == ISIS_SYSTYPE_L2_IS))
hassof390d2c2004-09-10 20:48:21 +00002144 {
2145 /* an IS neighbour -> add it */
hassoaa4376e2005-09-26 17:39:48 +00002146 if (circuit->area->oldmetric)
2147 {
2148 is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
paul15935e92005-05-03 09:27:23 +00002149
hassoaa4376e2005-09-26 17:39:48 +00002150 memcpy (&is_neigh->neigh_id, adj->sysid, ISIS_SYS_ID_LEN);
2151 listnode_add (lsp->tlv_data.is_neighs, is_neigh);
Christian Franke80a8f722015-11-12 14:21:47 +01002152 lsp_debug("ISIS (%s): Adding %s.%02x as old-style neighbor (peer)",
2153 area->area_tag, sysid_print(is_neigh->neigh_id),
2154 LSP_PSEUDO_ID(is_neigh->neigh_id));
hassoaa4376e2005-09-26 17:39:48 +00002155 }
2156 if (circuit->area->newmetric)
2157 {
2158 te_is_neigh = XCALLOC (MTYPE_ISIS_TLV,
2159 sizeof (struct te_is_neigh));
2160 memcpy (&te_is_neigh->neigh_id, adj->sysid, ISIS_SYS_ID_LEN);
2161 listnode_add (lsp->tlv_data.te_is_neighs, te_is_neigh);
Christian Franke80a8f722015-11-12 14:21:47 +01002162 lsp_debug("ISIS (%s): Adding %s.%02x as te-style neighbor (peer)",
2163 area->area_tag, sysid_print(te_is_neigh->neigh_id),
2164 LSP_PSEUDO_ID(te_is_neigh->neigh_id));
hassoaa4376e2005-09-26 17:39:48 +00002165 }
hassof390d2c2004-09-10 20:48:21 +00002166 }
Josh Bailey3f045a02012-03-24 08:35:20 -07002167 else if (level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_ES)
hassof390d2c2004-09-10 20:48:21 +00002168 {
2169 /* an ES neigbour add it, if we are building level 1 LSP */
2170 /* FIXME: the tlv-format is hard to use here */
2171 if (lsp->tlv_data.es_neighs == NULL)
2172 {
2173 lsp->tlv_data.es_neighs = list_new ();
2174 lsp->tlv_data.es_neighs->del = free_tlv;
2175 }
paul15935e92005-05-03 09:27:23 +00002176 es_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct es_neigh));
2177
hassof390d2c2004-09-10 20:48:21 +00002178 memcpy (&es_neigh->first_es_neigh, adj->sysid, ISIS_SYS_ID_LEN);
hassoaac372f2005-09-01 17:52:33 +00002179 listnode_add (lsp->tlv_data.es_neighs, es_neigh);
Christian Franke80a8f722015-11-12 14:21:47 +01002180 lsp_debug("ISIS (%s): Adding %s as ES neighbor (peer)",
2181 area->area_tag, sysid_print(es_neigh->first_es_neigh));
hassof390d2c2004-09-10 20:48:21 +00002182 }
Christian Franke80a8f722015-11-12 14:21:47 +01002183 else
2184 {
2185 lsp_debug("ISIS (%s): Ignoring neighbor %s, level does not match",
2186 area->area_tag, sysid_print(adj->sysid));
2187 }
2188 }
2189 else
2190 {
2191 lsp_debug("ISIS (%s): Ignoring neighbor %s, level does not intersect",
2192 area->area_tag, sysid_print(adj->sysid));
hassof390d2c2004-09-10 20:48:21 +00002193 }
jardineb5d44e2003-12-23 08:09:43 +00002194 }
Josh Bailey3f045a02012-03-24 08:35:20 -07002195 list_delete (adj_list);
hassof390d2c2004-09-10 20:48:21 +00002196
Christian Franke80a8f722015-11-12 14:21:47 +01002197 lsp_debug("ISIS (%s): Pseudo LSP construction is complete.", area->area_tag);
2198
hassoc0fb2a52005-09-03 16:29:40 +00002199 /* Reset endp of stream to overwrite only TLV part of it. */
hassoc89c05d2005-09-04 21:36:36 +00002200 stream_reset (lsp->pdu);
hassoc0fb2a52005-09-03 16:29:40 +00002201 stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
2202
jardineb5d44e2003-12-23 08:09:43 +00002203 /*
2204 * Add the authentication info if it's present
2205 */
Josh Bailey3f045a02012-03-24 08:35:20 -07002206 lsp_auth_add (lsp);
jardineb5d44e2003-12-23 08:09:43 +00002207
2208 if (lsp->tlv_data.is_neighs && listcount (lsp->tlv_data.is_neighs) > 0)
2209 tlv_add_is_neighs (lsp->tlv_data.is_neighs, lsp->pdu);
2210
hassoaa4376e2005-09-26 17:39:48 +00002211 if (lsp->tlv_data.te_is_neighs && listcount (lsp->tlv_data.te_is_neighs) > 0)
2212 tlv_add_te_is_neighs (lsp->tlv_data.te_is_neighs, lsp->pdu);
2213
jardineb5d44e2003-12-23 08:09:43 +00002214 if (lsp->tlv_data.es_neighs && listcount (lsp->tlv_data.es_neighs) > 0)
2215 tlv_add_is_neighs (lsp->tlv_data.es_neighs, lsp->pdu);
2216
paul9985f832005-02-09 15:51:56 +00002217 lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
hassof390d2c2004-09-10 20:48:21 +00002218
Josh Bailey3f045a02012-03-24 08:35:20 -07002219 /* Recompute authentication and checksum information */
2220 lsp_auth_update (lsp);
2221 fletcher_checksum(STREAM_DATA (lsp->pdu) + 12,
2222 ntohs (lsp->lsp_header->pdu_len) - 12, 12);
jardineb5d44e2003-12-23 08:09:43 +00002223
2224 return;
2225}
2226
Josh Bailey3f045a02012-03-24 08:35:20 -07002227int
2228lsp_generate_pseudo (struct isis_circuit *circuit, int level)
jardineb5d44e2003-12-23 08:09:43 +00002229{
2230 dict_t *lspdb = circuit->area->lspdb[level - 1];
2231 struct isis_lsp *lsp;
2232 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
Josh Bailey3f045a02012-03-24 08:35:20 -07002233 u_int16_t rem_lifetime, refresh_time;
2234
2235 if ((circuit->is_type & level) != level ||
2236 (circuit->state != C_STATE_UP) ||
2237 (circuit->circ_type != CIRCUIT_T_BROADCAST) ||
2238 (circuit->u.bc.is_dr[level - 1] == 0))
2239 return ISIS_ERROR;
2240
2241 memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
2242 LSP_FRAGMENT (lsp_id) = 0;
2243 LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id;
2244
2245 /*
2246 * If for some reason have a pseudo LSP in the db already -> regenerate
2247 */
2248 if (lsp_search (lsp_id, lspdb))
2249 return lsp_regenerate_schedule_pseudo (circuit, level);
2250
2251 rem_lifetime = lsp_rem_lifetime (circuit->area, level);
2252 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
Christian Frankef1fc1db2015-11-10 18:43:31 +01002253 lsp = lsp_new (circuit->area, lsp_id, rem_lifetime, 1,
Amritha Nambiarc8ee9402015-08-24 16:40:14 -07002254 circuit->area->is_type | circuit->area->attached_bit,
2255 0, level);
Josh Bailey3f045a02012-03-24 08:35:20 -07002256 lsp->area = circuit->area;
2257
2258 lsp_build_pseudo (lsp, circuit, level);
2259
2260 lsp->own_lsp = 1;
2261 lsp_insert (lsp, lspdb);
2262 lsp_set_all_srmflags (lsp);
2263
2264 refresh_time = lsp_refresh_time (lsp, rem_lifetime);
2265 THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
2266 circuit->lsp_regenerate_pending[level - 1] = 0;
2267 if (level == IS_LEVEL_1)
2268 THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1],
2269 lsp_l1_refresh_pseudo, circuit, refresh_time);
2270 else if (level == IS_LEVEL_2)
2271 THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1],
2272 lsp_l2_refresh_pseudo, circuit, refresh_time);
2273
2274 if (isis->debugs & DEBUG_UPDATE_PACKETS)
2275 {
2276 zlog_debug ("ISIS-Upd (%s): Building L%d Pseudo LSP %s, len %d, "
2277 "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us",
2278 circuit->area->area_tag, level,
2279 rawlspid_print (lsp->lsp_header->lsp_id),
2280 ntohl (lsp->lsp_header->pdu_len),
2281 ntohl (lsp->lsp_header->seq_num),
2282 ntohs (lsp->lsp_header->checksum),
2283 ntohs (lsp->lsp_header->rem_lifetime),
2284 refresh_time);
2285 }
2286
2287 return ISIS_OK;
2288}
2289
2290static int
2291lsp_regenerate_pseudo (struct isis_circuit *circuit, int level)
2292{
2293 dict_t *lspdb = circuit->area->lspdb[level - 1];
2294 struct isis_lsp *lsp;
2295 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
2296 u_int16_t rem_lifetime, refresh_time;
2297
2298 if ((circuit->is_type & level) != level ||
2299 (circuit->state != C_STATE_UP) ||
2300 (circuit->circ_type != CIRCUIT_T_BROADCAST) ||
2301 (circuit->u.bc.is_dr[level - 1] == 0))
2302 return ISIS_ERROR;
hassof390d2c2004-09-10 20:48:21 +00002303
jardineb5d44e2003-12-23 08:09:43 +00002304 memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
hassof390d2c2004-09-10 20:48:21 +00002305 LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id;
2306 LSP_FRAGMENT (lsp_id) = 0;
2307
jardineb5d44e2003-12-23 08:09:43 +00002308 lsp = lsp_search (lsp_id, lspdb);
hassof390d2c2004-09-10 20:48:21 +00002309
2310 if (!lsp)
2311 {
Josh Bailey3f045a02012-03-24 08:35:20 -07002312 zlog_err ("lsp_regenerate_pseudo: no l%d LSP %s found!",
2313 level, rawlspid_print (lsp_id));
hassof390d2c2004-09-10 20:48:21 +00002314 return ISIS_ERROR;
2315 }
2316 lsp_clear_data (lsp);
jardineb5d44e2003-12-23 08:09:43 +00002317
2318 lsp_build_pseudo (lsp, circuit, level);
2319
Josh Bailey3f045a02012-03-24 08:35:20 -07002320 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
Amritha Nambiarc8ee9402015-08-24 16:40:14 -07002321 lsp->lsp_header->lsp_bits = lsp_bits_generate (level, 0,
2322 circuit->area->attached_bit);
Josh Bailey3f045a02012-03-24 08:35:20 -07002323 rem_lifetime = lsp_rem_lifetime (circuit->area, level);
2324 lsp->lsp_header->rem_lifetime = htons (rem_lifetime);
jardineb5d44e2003-12-23 08:09:43 +00002325 lsp_inc_seqnum (lsp, 0);
Josh Bailey3f045a02012-03-24 08:35:20 -07002326 lsp->last_generated = time (NULL);
2327 lsp_set_all_srmflags (lsp);
2328
2329 refresh_time = lsp_refresh_time (lsp, rem_lifetime);
2330 if (level == IS_LEVEL_1)
2331 THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1],
2332 lsp_l1_refresh_pseudo, circuit, refresh_time);
2333 else if (level == IS_LEVEL_2)
2334 THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1],
2335 lsp_l2_refresh_pseudo, circuit, refresh_time);
hassof390d2c2004-09-10 20:48:21 +00002336
2337 if (isis->debugs & DEBUG_UPDATE_PACKETS)
2338 {
Josh Bailey3f045a02012-03-24 08:35:20 -07002339 zlog_debug ("ISIS-Upd (%s): Refreshing L%d Pseudo LSP %s, len %d, "
2340 "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us",
2341 circuit->area->area_tag, level,
2342 rawlspid_print (lsp->lsp_header->lsp_id),
2343 ntohl (lsp->lsp_header->pdu_len),
2344 ntohl (lsp->lsp_header->seq_num),
2345 ntohs (lsp->lsp_header->checksum),
2346 ntohs (lsp->lsp_header->rem_lifetime),
2347 refresh_time);
hassof390d2c2004-09-10 20:48:21 +00002348 }
jardineb5d44e2003-12-23 08:09:43 +00002349
jardineb5d44e2003-12-23 08:09:43 +00002350 return ISIS_OK;
2351}
2352
Josh Bailey3f045a02012-03-24 08:35:20 -07002353/*
2354 * Something has changed or periodic refresh -> regenerate pseudo LSP
2355 */
2356static int
jardineb5d44e2003-12-23 08:09:43 +00002357lsp_l1_refresh_pseudo (struct thread *thread)
2358{
2359 struct isis_circuit *circuit;
Josh Bailey3f045a02012-03-24 08:35:20 -07002360 u_char id[ISIS_SYS_ID_LEN + 2];
jardineb5d44e2003-12-23 08:09:43 +00002361
hassof390d2c2004-09-10 20:48:21 +00002362 circuit = THREAD_ARG (thread);
2363
hasso13c48f72004-09-10 21:19:13 +00002364 circuit->u.bc.t_refresh_pseudo_lsp[0] = NULL;
Josh Bailey3f045a02012-03-24 08:35:20 -07002365 circuit->lsp_regenerate_pending[0] = 0;
hasso13c48f72004-09-10 21:19:13 +00002366
Josh Bailey3f045a02012-03-24 08:35:20 -07002367 if ((circuit->u.bc.is_dr[0] == 0) ||
2368 (circuit->is_type & IS_LEVEL_1) == 0)
2369 {
2370 memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
2371 LSP_PSEUDO_ID (id) = circuit->circuit_id;
2372 LSP_FRAGMENT (id) = 0;
2373 lsp_purge_pseudo (id, circuit, IS_LEVEL_1);
2374 return ISIS_ERROR;
2375 }
hassof390d2c2004-09-10 20:48:21 +00002376
Josh Bailey3f045a02012-03-24 08:35:20 -07002377 return lsp_regenerate_pseudo (circuit, IS_LEVEL_1);
jardineb5d44e2003-12-23 08:09:43 +00002378}
2379
Josh Bailey3f045a02012-03-24 08:35:20 -07002380static int
jardineb5d44e2003-12-23 08:09:43 +00002381lsp_l2_refresh_pseudo (struct thread *thread)
2382{
2383 struct isis_circuit *circuit;
Josh Bailey3f045a02012-03-24 08:35:20 -07002384 u_char id[ISIS_SYS_ID_LEN + 2];
2385
hassof390d2c2004-09-10 20:48:21 +00002386 circuit = THREAD_ARG (thread);
2387
hasso13c48f72004-09-10 21:19:13 +00002388 circuit->u.bc.t_refresh_pseudo_lsp[1] = NULL;
Josh Bailey3f045a02012-03-24 08:35:20 -07002389 circuit->lsp_regenerate_pending[1] = 0;
hasso13c48f72004-09-10 21:19:13 +00002390
Josh Bailey3f045a02012-03-24 08:35:20 -07002391 if ((circuit->u.bc.is_dr[1] == 0) ||
2392 (circuit->is_type & IS_LEVEL_2) == 0)
2393 {
2394 memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
2395 LSP_PSEUDO_ID (id) = circuit->circuit_id;
2396 LSP_FRAGMENT (id) = 0;
2397 lsp_purge_pseudo (id, circuit, IS_LEVEL_2);
2398 return ISIS_ERROR;
2399 }
jardineb5d44e2003-12-23 08:09:43 +00002400
Josh Bailey3f045a02012-03-24 08:35:20 -07002401 return lsp_regenerate_pseudo (circuit, IS_LEVEL_2);
jardineb5d44e2003-12-23 08:09:43 +00002402}
2403
hassof390d2c2004-09-10 20:48:21 +00002404int
Josh Bailey3f045a02012-03-24 08:35:20 -07002405lsp_regenerate_schedule_pseudo (struct isis_circuit *circuit, int level)
jardineb5d44e2003-12-23 08:09:43 +00002406{
2407 struct isis_lsp *lsp;
Josh Bailey3f045a02012-03-24 08:35:20 -07002408 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
2409 time_t now, diff;
Christian Franke61010c32015-11-10 18:43:34 +01002410 long timeout;
Josh Bailey3f045a02012-03-24 08:35:20 -07002411 int lvl;
Christian Franke61010c32015-11-10 18:43:34 +01002412 struct isis_area *area = circuit->area;
jardineb5d44e2003-12-23 08:09:43 +00002413
Josh Bailey3f045a02012-03-24 08:35:20 -07002414 if (circuit == NULL ||
2415 circuit->circ_type != CIRCUIT_T_BROADCAST ||
2416 circuit->state != C_STATE_UP)
2417 return ISIS_OK;
jardineb5d44e2003-12-23 08:09:43 +00002418
Christian Franke61010c32015-11-10 18:43:34 +01002419 sched_debug("ISIS (%s): Scheduling regeneration of %s pseudo LSP for interface %s",
2420 area->area_tag, circuit_t2string(level), circuit->interface->name);
2421
Josh Bailey3f045a02012-03-24 08:35:20 -07002422 memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
2423 LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id;
2424 LSP_FRAGMENT (lsp_id) = 0;
2425 now = time (NULL);
jardineb5d44e2003-12-23 08:09:43 +00002426
Josh Bailey3f045a02012-03-24 08:35:20 -07002427 for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++)
2428 {
Christian Franke61010c32015-11-10 18:43:34 +01002429 sched_debug("ISIS (%s): Checking whether L%d pseudo LSP needs to be scheduled",
2430 area->area_tag, lvl);
jardineb5d44e2003-12-23 08:09:43 +00002431
Christian Franke61010c32015-11-10 18:43:34 +01002432 if (!((level & lvl) && (circuit->is_type & lvl)))
2433 {
2434 sched_debug("ISIS (%s): Level is not active on circuit",
2435 area->area_tag);
2436 continue;
2437 }
2438
2439 if (circuit->u.bc.is_dr[lvl - 1] == 0)
2440 {
2441 sched_debug("ISIS (%s): This IS is not DR, nothing to do.",
2442 area->area_tag);
2443 continue;
2444 }
2445
2446 if (circuit->lsp_regenerate_pending[lvl - 1])
2447 {
2448 struct timeval remain =
2449 thread_timer_remain(circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
2450 sched_debug("ISIS (%s): Regenerate is already pending, nothing todo."
2451 " (Due in %lld.%03lld seconds)", area->area_tag,
2452 (long long)remain.tv_sec, (long long)remain.tv_usec/1000);
2453 continue;
2454 }
hassof390d2c2004-09-10 20:48:21 +00002455
Josh Bailey3f045a02012-03-24 08:35:20 -07002456 lsp = lsp_search (lsp_id, circuit->area->lspdb[lvl - 1]);
2457 if (!lsp)
Christian Franke61010c32015-11-10 18:43:34 +01002458 {
2459 sched_debug("ISIS (%s): Pseudonode LSP does not exist yet, nothing to regenerate.",
2460 area->area_tag);
2461 continue;
2462 }
jardineb5d44e2003-12-23 08:09:43 +00002463
Josh Bailey3f045a02012-03-24 08:35:20 -07002464 /*
2465 * Throttle avoidance
2466 */
Christian Franke61010c32015-11-10 18:43:34 +01002467 sched_debug("ISIS (%s): Will schedule PSN regen timer. Last run was: %lld, Now is: %lld",
2468 area->area_tag, (long long)lsp->last_generated, (long long) now);
Josh Bailey3f045a02012-03-24 08:35:20 -07002469 THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
2470 diff = now - lsp->last_generated;
2471 if (diff < circuit->area->lsp_gen_interval[lvl - 1])
2472 {
Christian Franke61010c32015-11-10 18:43:34 +01002473 timeout = 1000 * (circuit->area->lsp_gen_interval[lvl - 1] - diff);
2474 sched_debug("ISIS (%s): Sechduling in %ld ms to match configured lsp_gen_interval",
2475 area->area_tag, timeout);
Josh Bailey3f045a02012-03-24 08:35:20 -07002476 }
2477 else
2478 {
Christian Franke61010c32015-11-10 18:43:34 +01002479 timeout = 100;
2480 sched_debug("ISIS (%s): Last generation was more than lsp_gen_interval ago."
2481 " Scheduling for execution in %ld ms.", area->area_tag, timeout);
2482 }
2483
2484 circuit->lsp_regenerate_pending[lvl - 1] = 1;
2485
2486 if (lvl == IS_LEVEL_1)
2487 {
2488 THREAD_TIMER_MSEC_ON(master,
2489 circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1],
2490 lsp_l1_refresh_pseudo, circuit, timeout);
2491 }
2492 else if (lvl == IS_LEVEL_2)
2493 {
2494 THREAD_TIMER_MSEC_ON(master,
2495 circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1],
2496 lsp_l2_refresh_pseudo, circuit, timeout);
Josh Bailey3f045a02012-03-24 08:35:20 -07002497 }
2498 }
jardineb5d44e2003-12-23 08:09:43 +00002499
Josh Bailey3f045a02012-03-24 08:35:20 -07002500 return ISIS_OK;
jardineb5d44e2003-12-23 08:09:43 +00002501}
2502
jardineb5d44e2003-12-23 08:09:43 +00002503/*
2504 * Walk through LSPs for an area
2505 * - set remaining lifetime
2506 * - set LSPs with SRMflag set for sending
2507 */
hassof390d2c2004-09-10 20:48:21 +00002508int
jardineb5d44e2003-12-23 08:09:43 +00002509lsp_tick (struct thread *thread)
2510{
2511 struct isis_area *area;
2512 struct isis_circuit *circuit;
2513 struct isis_lsp *lsp;
2514 struct list *lsp_list;
hasso3fdb2dd2005-09-28 18:45:54 +00002515 struct listnode *lspnode, *cnode;
jardineb5d44e2003-12-23 08:09:43 +00002516 dnode_t *dnode, *dnode_next;
2517 int level;
Josh Bailey3f045a02012-03-24 08:35:20 -07002518 u_int16_t rem_lifetime;
jardineb5d44e2003-12-23 08:09:43 +00002519
2520 lsp_list = list_new ();
hassof390d2c2004-09-10 20:48:21 +00002521
jardineb5d44e2003-12-23 08:09:43 +00002522 area = THREAD_ARG (thread);
2523 assert (area);
hasso13c48f72004-09-10 21:19:13 +00002524 area->t_tick = NULL;
hassof390d2c2004-09-10 20:48:21 +00002525 THREAD_TIMER_ON (master, area->t_tick, lsp_tick, area, 1);
jardineb5d44e2003-12-23 08:09:43 +00002526
2527 /*
2528 * Build a list of LSPs with (any) SRMflag set
2529 * and removed the ones that have aged out
2530 */
hassof390d2c2004-09-10 20:48:21 +00002531 for (level = 0; level < ISIS_LEVELS; level++)
2532 {
2533 if (area->lspdb[level] && dict_count (area->lspdb[level]) > 0)
Josh Bailey3f045a02012-03-24 08:35:20 -07002534 {
2535 for (dnode = dict_first (area->lspdb[level]);
2536 dnode != NULL; dnode = dnode_next)
2537 {
2538 dnode_next = dict_next (area->lspdb[level], dnode);
2539 lsp = dnode_get (dnode);
jardineb5d44e2003-12-23 08:09:43 +00002540
Josh Bailey3f045a02012-03-24 08:35:20 -07002541 /*
2542 * The lsp rem_lifetime is kept at 0 for MaxAge or
2543 * ZeroAgeLifetime depending on explicit purge or
2544 * natural age out. So schedule spf only once when
2545 * the first time rem_lifetime becomes 0.
2546 */
2547 rem_lifetime = ntohs(lsp->lsp_header->rem_lifetime);
2548 lsp_set_time (lsp);
2549
2550 /*
2551 * Schedule may run spf which should be done only after
2552 * the lsp rem_lifetime becomes 0 for the first time.
2553 * ISO 10589 - 7.3.16.4 first paragraph.
2554 */
2555 if (rem_lifetime == 1 && lsp->lsp_header->seq_num != 0)
2556 {
2557 /* 7.3.16.4 a) set SRM flags on all */
2558 lsp_set_all_srmflags (lsp);
2559 /* 7.3.16.4 b) retain only the header FIXME */
2560 /* 7.3.16.4 c) record the time to purge FIXME */
2561 /* run/schedule spf */
2562 /* isis_spf_schedule is called inside lsp_destroy() below;
2563 * so it is not needed here. */
2564 /* isis_spf_schedule (lsp->area, lsp->level); */
2565 }
2566
2567 if (lsp->age_out == 0)
2568 {
2569 zlog_debug ("ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out",
2570 area->area_tag,
2571 lsp->level,
2572 rawlspid_print (lsp->lsp_header->lsp_id),
2573 ntohl (lsp->lsp_header->seq_num));
hassof1082d12005-09-19 04:23:34 +00002574#ifdef TOPOLOGY_GENERATE
Josh Bailey3f045a02012-03-24 08:35:20 -07002575 if (lsp->from_topology)
2576 THREAD_TIMER_OFF (lsp->t_lsp_top_ref);
hassof1082d12005-09-19 04:23:34 +00002577#endif /* TOPOLOGY_GENERATE */
Josh Bailey3f045a02012-03-24 08:35:20 -07002578 lsp_destroy (lsp);
2579 lsp = NULL;
2580 dict_delete_free (area->lspdb[level], dnode);
2581 }
2582 else if (flags_any_set (lsp->SRMflags))
2583 listnode_add (lsp_list, lsp);
2584 }
jardineb5d44e2003-12-23 08:09:43 +00002585
Josh Bailey3f045a02012-03-24 08:35:20 -07002586 /*
2587 * Send LSPs on circuits indicated by the SRMflags
2588 */
2589 if (listcount (lsp_list) > 0)
2590 {
paul1eb8ef22005-04-07 07:30:20 +00002591 for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit))
Josh Bailey3f045a02012-03-24 08:35:20 -07002592 {
2593 int diff = time (NULL) - circuit->lsp_queue_last_cleared;
2594 if (circuit->lsp_queue == NULL ||
2595 diff < MIN_LSP_TRANS_INTERVAL)
2596 continue;
hasso3fdb2dd2005-09-28 18:45:54 +00002597 for (ALL_LIST_ELEMENTS_RO (lsp_list, lspnode, lsp))
Josh Bailey3f045a02012-03-24 08:35:20 -07002598 {
2599 if (circuit->upadjcount[lsp->level - 1] &&
2600 ISIS_CHECK_FLAG (lsp->SRMflags, circuit))
2601 {
2602 /* Add the lsp only if it is not already in lsp
2603 * queue */
2604 if (! listnode_lookup (circuit->lsp_queue, lsp))
2605 {
2606 listnode_add (circuit->lsp_queue, lsp);
2607 thread_add_event (master, send_lsp, circuit, 0);
2608 }
2609 }
2610 }
2611 }
2612 list_delete_all_node (lsp_list);
2613 }
2614 }
jardineb5d44e2003-12-23 08:09:43 +00002615 }
jardineb5d44e2003-12-23 08:09:43 +00002616
2617 list_delete (lsp_list);
2618
2619 return ISIS_OK;
2620}
2621
jardineb5d44e2003-12-23 08:09:43 +00002622void
Josh Bailey3f045a02012-03-24 08:35:20 -07002623lsp_purge_pseudo (u_char * id, struct isis_circuit *circuit, int level)
jardineb5d44e2003-12-23 08:09:43 +00002624{
2625 struct isis_lsp *lsp;
Josh Bailey3f045a02012-03-24 08:35:20 -07002626 u_int16_t seq_num;
2627 u_int8_t lsp_bits;
hassof390d2c2004-09-10 20:48:21 +00002628
jardineb5d44e2003-12-23 08:09:43 +00002629 lsp = lsp_search (id, circuit->area->lspdb[level - 1]);
Josh Bailey3f045a02012-03-24 08:35:20 -07002630 if (!lsp)
2631 return;
hassof390d2c2004-09-10 20:48:21 +00002632
Josh Bailey3f045a02012-03-24 08:35:20 -07002633 /* store old values */
2634 seq_num = lsp->lsp_header->seq_num;
2635 lsp_bits = lsp->lsp_header->lsp_bits;
2636
2637 /* reset stream */
2638 lsp_clear_data (lsp);
2639 stream_reset (lsp->pdu);
2640
2641 /* update header */
2642 lsp->lsp_header->pdu_len = htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
2643 memcpy (lsp->lsp_header->lsp_id, id, ISIS_SYS_ID_LEN + 2);
2644 lsp->lsp_header->checksum = 0;
2645 lsp->lsp_header->seq_num = seq_num;
2646 lsp->lsp_header->rem_lifetime = 0;
2647 lsp->lsp_header->lsp_bits = lsp_bits;
2648 lsp->level = level;
2649 lsp->age_out = lsp->area->max_lsp_lifetime[level-1];
2650 stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
2651
2652 /*
2653 * Add and update the authentication info if its present
2654 */
2655 lsp_auth_add (lsp);
2656 lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
2657 lsp_auth_update (lsp);
2658 fletcher_checksum(STREAM_DATA (lsp->pdu) + 12,
2659 ntohs (lsp->lsp_header->pdu_len) - 12, 12);
2660
2661 lsp_set_all_srmflags (lsp);
hassof390d2c2004-09-10 20:48:21 +00002662
jardineb5d44e2003-12-23 08:09:43 +00002663 return;
2664}
2665
2666/*
2667 * Purge own LSP that is received and we don't have.
2668 * -> Do as in 7.3.16.4
2669 */
2670void
Christian Franke749e87a2015-11-10 18:21:44 +01002671lsp_purge_non_exist (int level,
2672 struct isis_link_state_hdr *lsp_hdr,
hassof390d2c2004-09-10 20:48:21 +00002673 struct isis_area *area)
jardineb5d44e2003-12-23 08:09:43 +00002674{
2675 struct isis_lsp *lsp;
2676
2677 /*
2678 * We need to create the LSP to be purged
2679 */
hassoaac372f2005-09-01 17:52:33 +00002680 lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp));
Josh Bailey3f045a02012-03-24 08:35:20 -07002681 lsp->area = area;
Christian Franke749e87a2015-11-10 18:21:44 +01002682 lsp->level = level;
Christian Frankef1fc1db2015-11-10 18:43:31 +01002683 lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu);
hassof390d2c2004-09-10 20:48:21 +00002684 lsp->isis_header = (struct isis_fixed_hdr *) STREAM_DATA (lsp->pdu);
Josh Bailey3f045a02012-03-24 08:35:20 -07002685 fill_fixed_hdr (lsp->isis_header, (lsp->level == IS_LEVEL_1) ? L1_LINK_STATE
hassof390d2c2004-09-10 20:48:21 +00002686 : L2_LINK_STATE);
2687 lsp->lsp_header = (struct isis_link_state_hdr *) (STREAM_DATA (lsp->pdu) +
2688 ISIS_FIXED_HDR_LEN);
jardineb5d44e2003-12-23 08:09:43 +00002689 memcpy (lsp->lsp_header, lsp_hdr, ISIS_LSP_HDR_LEN);
Josh Bailey3f045a02012-03-24 08:35:20 -07002690 stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
hassof390d2c2004-09-10 20:48:21 +00002691
jardineb5d44e2003-12-23 08:09:43 +00002692 /*
jardineb5d44e2003-12-23 08:09:43 +00002693 * Set the remaining lifetime to 0
2694 */
2695 lsp->lsp_header->rem_lifetime = 0;
Josh Bailey3f045a02012-03-24 08:35:20 -07002696
2697 /*
2698 * Add and update the authentication info if its present
2699 */
2700 lsp_auth_add (lsp);
2701 lsp_auth_update (lsp);
2702
2703 /*
2704 * Update the PDU length to header plus any authentication TLV.
2705 */
2706 lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
2707
jardineb5d44e2003-12-23 08:09:43 +00002708 /*
2709 * Put the lsp into LSPdb
2710 */
hassof390d2c2004-09-10 20:48:21 +00002711 lsp_insert (lsp, area->lspdb[lsp->level - 1]);
jardineb5d44e2003-12-23 08:09:43 +00002712
2713 /*
2714 * Send in to whole area
2715 */
Josh Bailey3f045a02012-03-24 08:35:20 -07002716 lsp_set_all_srmflags (lsp);
hassof390d2c2004-09-10 20:48:21 +00002717
jardineb5d44e2003-12-23 08:09:43 +00002718 return;
2719}
2720
Josh Bailey3f045a02012-03-24 08:35:20 -07002721void lsp_set_all_srmflags (struct isis_lsp *lsp)
2722{
2723 struct listnode *node;
2724 struct isis_circuit *circuit;
2725
2726 assert (lsp);
2727
2728 ISIS_FLAGS_CLEAR_ALL(lsp->SRMflags);
2729
2730 if (lsp->area)
2731 {
2732 struct list *circuit_list = lsp->area->circuit_list;
2733 for (ALL_LIST_ELEMENTS_RO (circuit_list, node, circuit))
2734 {
2735 ISIS_SET_FLAG(lsp->SRMflags, circuit);
2736 }
2737 }
2738}
2739
jardineb5d44e2003-12-23 08:09:43 +00002740#ifdef TOPOLOGY_GENERATE
hasso92365882005-01-18 13:53:33 +00002741static int
jardineb5d44e2003-12-23 08:09:43 +00002742top_lsp_refresh (struct thread *thread)
2743{
hassof390d2c2004-09-10 20:48:21 +00002744 struct isis_lsp *lsp;
David Lamparterf50ee932015-03-04 07:13:38 +01002745 u_int16_t rem_lifetime;
jardineb5d44e2003-12-23 08:09:43 +00002746
2747 lsp = THREAD_ARG (thread);
2748 assert (lsp);
2749
2750 lsp->t_lsp_top_ref = NULL;
2751
hassof1082d12005-09-19 04:23:34 +00002752 lsp_seqnum_update (lsp);
jardineb5d44e2003-12-23 08:09:43 +00002753
Josh Bailey3f045a02012-03-24 08:35:20 -07002754 lsp_set_all_srmflags (lsp);
hassof390d2c2004-09-10 20:48:21 +00002755 if (isis->debugs & DEBUG_UPDATE_PACKETS)
2756 {
hasso529d65b2004-12-24 00:14:50 +00002757 zlog_debug ("ISIS-Upd (): refreshing Topology L1 %s",
2758 rawlspid_print (lsp->lsp_header->lsp_id));
hassof390d2c2004-09-10 20:48:21 +00002759 }
hassod3d74742005-09-28 18:30:51 +00002760 /* Refresh dynamic hostname in the cache. */
2761 isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname,
2762 IS_LEVEL_1);
2763
David Lampartera47c5832012-06-21 09:55:38 +02002764 lsp->lsp_header->lsp_bits = lsp_bits_generate (lsp->level,
Amritha Nambiarc8ee9402015-08-24 16:40:14 -07002765 lsp->area->overload_bit,
2766 lsp->area->attached_bit);
Josh Bailey3f045a02012-03-24 08:35:20 -07002767 rem_lifetime = lsp_rem_lifetime (lsp->area, IS_LEVEL_1);
2768 lsp->lsp_header->rem_lifetime = htons (rem_lifetime);
jardineb5d44e2003-12-23 08:09:43 +00002769
David Lamparterf50ee932015-03-04 07:13:38 +01002770 /* refresh_time = lsp_refresh_time (lsp, rem_lifetime); */
hassof390d2c2004-09-10 20:48:21 +00002771 THREAD_TIMER_ON (master, lsp->t_lsp_top_ref, top_lsp_refresh, lsp,
Josh Bailey3f045a02012-03-24 08:35:20 -07002772 lsp->area->lsp_refresh[0]);
jardineb5d44e2003-12-23 08:09:43 +00002773
2774 return ISIS_OK;
2775}
2776
2777void
2778generate_topology_lsps (struct isis_area *area)
2779{
2780 struct listnode *node;
2781 int i, max = 0;
2782 struct arc *arc;
2783 u_char lspid[ISIS_SYS_ID_LEN + 2];
2784 struct isis_lsp *lsp;
Josh Bailey3f045a02012-03-24 08:35:20 -07002785 u_int16_t rem_lifetime, refresh_time;
jardineb5d44e2003-12-23 08:09:43 +00002786
2787 /* first we find the maximal node */
paula8f03df2005-04-10 15:58:10 +00002788 for (ALL_LIST_ELEMENTS_RO (area->topology, node, arc))
Josh Bailey3f045a02012-03-24 08:35:20 -07002789 {
2790 if (arc->from_node > max)
2791 max = arc->from_node;
2792 if (arc->to_node > max)
2793 max = arc->to_node;
2794 }
jardineb5d44e2003-12-23 08:09:43 +00002795
hassof390d2c2004-09-10 20:48:21 +00002796 for (i = 1; i < (max + 1); i++)
2797 {
2798 memcpy (lspid, area->topology_baseis, ISIS_SYS_ID_LEN);
2799 LSP_PSEUDO_ID (lspid) = 0x00;
2800 LSP_FRAGMENT (lspid) = 0x00;
2801 lspid[ISIS_SYS_ID_LEN - 1] = (i & 0xFF);
2802 lspid[ISIS_SYS_ID_LEN - 2] = ((i >> 8) & 0xFF);
jardineb5d44e2003-12-23 08:09:43 +00002803
Josh Bailey3f045a02012-03-24 08:35:20 -07002804 rem_lifetime = lsp_rem_lifetime (area, IS_LEVEL_1);
Christian Frankef1fc1db2015-11-10 18:43:31 +01002805 lsp = lsp_new (area, lspid, rem_lifetime, 1,
2806 IS_LEVEL_1 | area->overload_bit | area->attached_bit,
2807 0, 1);
hassof1082d12005-09-19 04:23:34 +00002808 if (!lsp)
2809 return;
Josh Bailey3f045a02012-03-24 08:35:20 -07002810 lsp->from_topology = 1;
jardineb5d44e2003-12-23 08:09:43 +00002811
hassof1082d12005-09-19 04:23:34 +00002812 /* Creating LSP data based on topology info. */
2813 build_topology_lsp_data (lsp, area, i);
2814 /* Checksum is also calculated here. */
2815 lsp_seqnum_update (lsp);
hasso9551eea2005-09-28 18:26:25 +00002816 /* Take care of inserting dynamic hostname into cache. */
2817 isis_dynhn_insert (lspid, lsp->tlv_data.hostname, IS_LEVEL_1);
hassof1082d12005-09-19 04:23:34 +00002818
Josh Bailey3f045a02012-03-24 08:35:20 -07002819 refresh_time = lsp_refresh_time (lsp, rem_lifetime);
hassof1082d12005-09-19 04:23:34 +00002820 THREAD_TIMER_ON (master, lsp->t_lsp_top_ref, top_lsp_refresh, lsp,
Josh Bailey3f045a02012-03-24 08:35:20 -07002821 refresh_time);
2822 lsp_set_all_srmflags (lsp);
hassof390d2c2004-09-10 20:48:21 +00002823 lsp_insert (lsp, area->lspdb[0]);
hassof390d2c2004-09-10 20:48:21 +00002824 }
jardineb5d44e2003-12-23 08:09:43 +00002825}
2826
2827void
2828remove_topology_lsps (struct isis_area *area)
2829{
2830 struct isis_lsp *lsp;
2831 dnode_t *dnode, *dnode_next;
2832
2833 dnode = dict_first (area->lspdb[0]);
hassof390d2c2004-09-10 20:48:21 +00002834 while (dnode != NULL)
2835 {
2836 dnode_next = dict_next (area->lspdb[0], dnode);
2837 lsp = dnode_get (dnode);
2838 if (lsp->from_topology)
2839 {
2840 THREAD_TIMER_OFF (lsp->t_lsp_top_ref);
2841 lsp_destroy (lsp);
2842 dict_delete (area->lspdb[0], dnode);
2843 }
2844 dnode = dnode_next;
jardineb5d44e2003-12-23 08:09:43 +00002845 }
jardineb5d44e2003-12-23 08:09:43 +00002846}
2847
2848void
hassof390d2c2004-09-10 20:48:21 +00002849build_topology_lsp_data (struct isis_lsp *lsp, struct isis_area *area,
jardineb5d44e2003-12-23 08:09:43 +00002850 int lsp_top_num)
2851{
hasso3fdb2dd2005-09-28 18:45:54 +00002852 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +00002853 struct arc *arc;
jardineb5d44e2003-12-23 08:09:43 +00002854 struct is_neigh *is_neigh;
hasso9551eea2005-09-28 18:26:25 +00002855 struct te_is_neigh *te_is_neigh;
jardineb5d44e2003-12-23 08:09:43 +00002856 char buff[200];
hassof1082d12005-09-19 04:23:34 +00002857 struct tlvs tlv_data;
2858 struct isis_lsp *lsp0 = lsp;
jardineb5d44e2003-12-23 08:09:43 +00002859
hassof1082d12005-09-19 04:23:34 +00002860 /* Add area addresses. FIXME: Is it needed at all? */
2861 if (lsp->tlv_data.area_addrs == NULL)
2862 lsp->tlv_data.area_addrs = list_new ();
2863 list_add_list (lsp->tlv_data.area_addrs, area->area_addrs);
jardineb5d44e2003-12-23 08:09:43 +00002864
hassof1082d12005-09-19 04:23:34 +00002865 if (lsp->tlv_data.nlpids == NULL)
2866 lsp->tlv_data.nlpids = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct nlpids));
2867 lsp->tlv_data.nlpids->count = 1;
2868 lsp->tlv_data.nlpids->nlpids[0] = NLPID_IP;
jardineb5d44e2003-12-23 08:09:43 +00002869
hassof1082d12005-09-19 04:23:34 +00002870 if (area->dynhostname)
2871 {
2872 lsp->tlv_data.hostname = XMALLOC (MTYPE_ISIS_TLV,
2873 sizeof (struct hostname));
2874 memset (buff, 0x00, 200);
2875 sprintf (buff, "%s%d", area->topology_basedynh ? area->topology_basedynh :
2876 "feedme", lsp_top_num);
2877 memcpy (lsp->tlv_data.hostname->name, buff, strlen (buff));
2878 lsp->tlv_data.hostname->namelen = strlen (buff);
2879 }
2880
2881 if (lsp->tlv_data.nlpids)
2882 tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu);
2883 if (lsp->tlv_data.hostname)
2884 tlv_add_dynamic_hostname (lsp->tlv_data.hostname, lsp->pdu);
2885 if (lsp->tlv_data.area_addrs && listcount (lsp->tlv_data.area_addrs) > 0)
2886 tlv_add_area_addrs (lsp->tlv_data.area_addrs, lsp->pdu);
2887
2888 memset (&tlv_data, 0, sizeof (struct tlvs));
2889 if (tlv_data.is_neighs == NULL)
hasso9551eea2005-09-28 18:26:25 +00002890 {
2891 tlv_data.is_neighs = list_new ();
2892 tlv_data.is_neighs->del = free_tlv;
2893 }
hassof1082d12005-09-19 04:23:34 +00002894
2895 /* Add reachability for this IS for simulated 1. */
hassof390d2c2004-09-10 20:48:21 +00002896 if (lsp_top_num == 1)
2897 {
hasso3fdb2dd2005-09-28 18:45:54 +00002898 is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
hassof1082d12005-09-19 04:23:34 +00002899
hassof390d2c2004-09-10 20:48:21 +00002900 memcpy (&is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN);
jardineb5d44e2003-12-23 08:09:43 +00002901 LSP_PSEUDO_ID (is_neigh->neigh_id) = 0x00;
hassof1082d12005-09-19 04:23:34 +00002902 /* Metric MUST NOT be 0, unless it's not alias TLV. */
2903 is_neigh->metrics.metric_default = 0x01;
jardineb5d44e2003-12-23 08:09:43 +00002904 is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED;
2905 is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED;
2906 is_neigh->metrics.metric_error = METRICS_UNSUPPORTED;
hassof1082d12005-09-19 04:23:34 +00002907 listnode_add (tlv_data.is_neighs, is_neigh);
jardineb5d44e2003-12-23 08:09:43 +00002908 }
hassof390d2c2004-09-10 20:48:21 +00002909
hassof1082d12005-09-19 04:23:34 +00002910 /* Add IS reachabilities. */
hasso3fdb2dd2005-09-28 18:45:54 +00002911 for (ALL_LIST_ELEMENTS_RO (area->topology, node, arc))
hassof390d2c2004-09-10 20:48:21 +00002912 {
hassof1082d12005-09-19 04:23:34 +00002913 int to_lsp = 0;
2914
2915 if ((lsp_top_num != arc->from_node) && (lsp_top_num != arc->to_node))
2916 continue;
2917
2918 if (lsp_top_num == arc->from_node)
2919 to_lsp = arc->to_node;
2920 else
2921 to_lsp = arc->from_node;
2922
hasso9551eea2005-09-28 18:26:25 +00002923 if (area->oldmetric)
2924 {
2925 is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
hassof1082d12005-09-19 04:23:34 +00002926
hasso9551eea2005-09-28 18:26:25 +00002927 memcpy (&is_neigh->neigh_id, area->topology_baseis, ISIS_SYS_ID_LEN);
2928 is_neigh->neigh_id[ISIS_SYS_ID_LEN - 1] = (to_lsp & 0xFF);
2929 is_neigh->neigh_id[ISIS_SYS_ID_LEN - 2] = ((to_lsp >> 8) & 0xFF);
2930 is_neigh->metrics.metric_default = arc->distance;
2931 is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED;
2932 is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED;
2933 is_neigh->metrics.metric_error = METRICS_UNSUPPORTED;
2934 listnode_add (tlv_data.is_neighs, is_neigh);
2935 }
2936
2937 if (area->newmetric)
2938 {
hasso9551eea2005-09-28 18:26:25 +00002939 if (tlv_data.te_is_neighs == NULL)
2940 {
2941 tlv_data.te_is_neighs = list_new ();
2942 tlv_data.te_is_neighs->del = free_tlv;
2943 }
2944 te_is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct te_is_neigh));
2945 memcpy (&te_is_neigh->neigh_id, area->topology_baseis,
2946 ISIS_SYS_ID_LEN);
2947 te_is_neigh->neigh_id[ISIS_SYS_ID_LEN - 1] = (to_lsp & 0xFF);
2948 te_is_neigh->neigh_id[ISIS_SYS_ID_LEN - 2] = ((to_lsp >> 8) & 0xFF);
Josh Bailey3f045a02012-03-24 08:35:20 -07002949 SET_TE_METRIC(te_is_neigh, arc->distance);
hasso9551eea2005-09-28 18:26:25 +00002950 listnode_add (tlv_data.te_is_neighs, te_is_neigh);
2951 }
hassof390d2c2004-09-10 20:48:21 +00002952 }
hassof1082d12005-09-19 04:23:34 +00002953
2954 while (tlv_data.is_neighs && listcount (tlv_data.is_neighs))
2955 {
2956 if (lsp->tlv_data.is_neighs == NULL)
2957 lsp->tlv_data.is_neighs = list_new ();
hasso9551eea2005-09-28 18:26:25 +00002958 lsp_tlv_fit (lsp, &tlv_data.is_neighs, &lsp->tlv_data.is_neighs,
hassof1082d12005-09-19 04:23:34 +00002959 IS_NEIGHBOURS_LEN, area->lsp_frag_threshold,
2960 tlv_add_is_neighs);
2961 if (tlv_data.is_neighs && listcount (tlv_data.is_neighs))
2962 lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
2963 lsp0, area, IS_LEVEL_1);
2964 }
2965
hasso9551eea2005-09-28 18:26:25 +00002966 while (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs))
2967 {
2968 if (lsp->tlv_data.te_is_neighs == NULL)
2969 lsp->tlv_data.te_is_neighs = list_new ();
2970 lsp_tlv_fit (lsp, &tlv_data.te_is_neighs, &lsp->tlv_data.te_is_neighs,
2971 IS_NEIGHBOURS_LEN, area->lsp_frag_threshold,
2972 tlv_add_te_is_neighs);
2973 if (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs))
2974 lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
2975 lsp0, area, IS_LEVEL_1);
2976 }
2977
hassof1082d12005-09-19 04:23:34 +00002978 free_tlvs (&tlv_data);
2979 return;
jardineb5d44e2003-12-23 08:09:43 +00002980}
2981#endif /* TOPOLOGY_GENERATE */