blob: 4665490be20a3a472051933f3905dd9fc2e0d802 [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
boris yakubova0a661f2013-04-26 14:38:34 -0400140 if (lsp->area->circuit_list) {
141 for (ALL_LIST_ELEMENTS_RO (lsp->area->circuit_list, cnode, circuit))
142 {
143 if (circuit->lsp_queue == NULL)
144 continue;
145 for (ALL_LIST_ELEMENTS (circuit->lsp_queue, lnode, lnnode, lsp_in_list))
146 if (lsp_in_list == lsp)
147 list_delete_node(circuit->lsp_queue, lnode);
148 }
149 }
Josh Bailey3f045a02012-03-24 08:35:20 -0700150 ISIS_FLAGS_CLEAR_ALL (lsp->SSNflags);
151 ISIS_FLAGS_CLEAR_ALL (lsp->SRMflags);
152
jardineb5d44e2003-12-23 08:09:43 +0000153 lsp_clear_data (lsp);
hassof390d2c2004-09-10 20:48:21 +0000154
155 if (LSP_FRAGMENT (lsp->lsp_header->lsp_id) == 0 && lsp->lspu.frags)
156 {
jardineb5d44e2003-12-23 08:09:43 +0000157 list_delete (lsp->lspu.frags);
Josh Bailey3f045a02012-03-24 08:35:20 -0700158 lsp->lspu.frags = NULL;
hassof390d2c2004-09-10 20:48:21 +0000159 }
160
Josh Bailey3f045a02012-03-24 08:35:20 -0700161 isis_spf_schedule (lsp->area, lsp->level);
162#ifdef HAVE_IPV6
163 isis_spf_schedule6 (lsp->area, lsp->level);
164#endif
165
jardineb5d44e2003-12-23 08:09:43 +0000166 if (lsp->pdu)
167 stream_free (lsp->pdu);
168 XFREE (MTYPE_ISIS_LSP, lsp);
169}
170
hassof390d2c2004-09-10 20:48:21 +0000171void
172lsp_db_destroy (dict_t * lspdb)
jardineb5d44e2003-12-23 08:09:43 +0000173{
174 dnode_t *dnode, *next;
175 struct isis_lsp *lsp;
hassof390d2c2004-09-10 20:48:21 +0000176
jardineb5d44e2003-12-23 08:09:43 +0000177 dnode = dict_first (lspdb);
hassof390d2c2004-09-10 20:48:21 +0000178 while (dnode)
179 {
180 next = dict_next (lspdb, dnode);
181 lsp = dnode_get (dnode);
182 lsp_destroy (lsp);
183 dict_delete_free (lspdb, dnode);
184 dnode = next;
185 }
186
jardineb5d44e2003-12-23 08:09:43 +0000187 dict_free (lspdb);
hassof390d2c2004-09-10 20:48:21 +0000188
jardineb5d44e2003-12-23 08:09:43 +0000189 return;
190}
191
192/*
193 * Remove all the frags belonging to the given lsp
194 */
hasso92365882005-01-18 13:53:33 +0000195static void
hassof390d2c2004-09-10 20:48:21 +0000196lsp_remove_frags (struct list *frags, dict_t * lspdb)
jardineb5d44e2003-12-23 08:09:43 +0000197{
198 dnode_t *dnode;
paul1eb8ef22005-04-07 07:30:20 +0000199 struct listnode *lnode, *lnnode;
jardineb5d44e2003-12-23 08:09:43 +0000200 struct isis_lsp *lsp;
201
paul1eb8ef22005-04-07 07:30:20 +0000202 for (ALL_LIST_ELEMENTS (frags, lnode, lnnode, lsp))
hassof390d2c2004-09-10 20:48:21 +0000203 {
hassof390d2c2004-09-10 20:48:21 +0000204 dnode = dict_lookup (lspdb, lsp->lsp_header->lsp_id);
205 lsp_destroy (lsp);
206 dnode_destroy (dict_delete (lspdb, dnode));
207 }
208
jardineb5d44e2003-12-23 08:09:43 +0000209 list_delete_all_node (frags);
hassof390d2c2004-09-10 20:48:21 +0000210
jardineb5d44e2003-12-23 08:09:43 +0000211 return;
212}
213
214void
hassof390d2c2004-09-10 20:48:21 +0000215lsp_search_and_destroy (u_char * id, dict_t * lspdb)
jardineb5d44e2003-12-23 08:09:43 +0000216{
217 dnode_t *node;
218 struct isis_lsp *lsp;
219
220 node = dict_lookup (lspdb, id);
hassof390d2c2004-09-10 20:48:21 +0000221 if (node)
222 {
223 node = dict_delete (lspdb, node);
224 lsp = dnode_get (node);
225 /*
226 * If this is a zero lsp, remove all the frags now
227 */
228 if (LSP_FRAGMENT (lsp->lsp_header->lsp_id) == 0)
229 {
230 if (lsp->lspu.frags)
231 lsp_remove_frags (lsp->lspu.frags, lspdb);
232 }
233 else
234 {
235 /*
236 * else just remove this frag, from the zero lsps' frag list
237 */
238 if (lsp->lspu.zero_lsp && lsp->lspu.zero_lsp->lspu.frags)
239 listnode_delete (lsp->lspu.zero_lsp->lspu.frags, lsp);
240 }
241 lsp_destroy (lsp);
242 dnode_destroy (node);
jardineb5d44e2003-12-23 08:09:43 +0000243 }
jardineb5d44e2003-12-23 08:09:43 +0000244}
245
246/*
247 * Compares a LSP to given values
248 * Params are given in net order
249 */
hassof390d2c2004-09-10 20:48:21 +0000250int
251lsp_compare (char *areatag, struct isis_lsp *lsp, u_int32_t seq_num,
jardineb5d44e2003-12-23 08:09:43 +0000252 u_int16_t checksum, u_int16_t rem_lifetime)
253{
hassof390d2c2004-09-10 20:48:21 +0000254 /* no point in double ntohl on seqnum */
255 if (lsp->lsp_header->seq_num == seq_num &&
jardineb5d44e2003-12-23 08:09:43 +0000256 lsp->lsp_header->checksum == checksum &&
257 /*comparing with 0, no need to do ntohl */
258 ((lsp->lsp_header->rem_lifetime == 0 && rem_lifetime == 0) ||
hassof390d2c2004-09-10 20:48:21 +0000259 (lsp->lsp_header->rem_lifetime != 0 && rem_lifetime != 0)))
260 {
261 if (isis->debugs & DEBUG_SNP_PACKETS)
262 {
Josh Bailey3f045a02012-03-24 08:35:20 -0700263 zlog_debug ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x,"
hasso529d65b2004-12-24 00:14:50 +0000264 " lifetime %us",
265 areatag,
266 rawlspid_print (lsp->lsp_header->lsp_id),
267 ntohl (lsp->lsp_header->seq_num),
268 ntohs (lsp->lsp_header->checksum),
269 ntohs (lsp->lsp_header->rem_lifetime));
270 zlog_debug ("ISIS-Snp (%s): is equal to ours seq 0x%08x,"
271 " cksum 0x%04x, lifetime %us",
272 areatag,
273 ntohl (seq_num), ntohs (checksum), ntohs (rem_lifetime));
hassof390d2c2004-09-10 20:48:21 +0000274 }
275 return LSP_EQUAL;
jardineb5d44e2003-12-23 08:09:43 +0000276 }
jardineb5d44e2003-12-23 08:09:43 +0000277
Christian Franke80d6b4e2015-11-10 18:33:15 +0100278 /*
279 * LSPs with identical checksums should only be treated as newer if:
280 * a) The current LSP has a remaining lifetime != 0 and the other LSP has a
281 * remaining lifetime == 0. In this case, we should participate in the purge
282 * and should not treat the current LSP with remaining lifetime == 0 as older.
283 * b) The LSP has an incorrect checksum. In this case, we need to react as given
284 * in 7.3.16.2.
285 */
286 if (ntohl (seq_num) > ntohl (lsp->lsp_header->seq_num)
287 || (ntohl(seq_num) == ntohl(lsp->lsp_header->seq_num)
288 && ( (lsp->lsp_header->rem_lifetime != 0
289 && rem_lifetime == 0)
290 || lsp->lsp_header->checksum != checksum)))
hassof390d2c2004-09-10 20:48:21 +0000291 {
292 if (isis->debugs & DEBUG_SNP_PACKETS)
293 {
Josh Bailey3f045a02012-03-24 08:35:20 -0700294 zlog_debug ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x,"
hasso529d65b2004-12-24 00:14:50 +0000295 " lifetime %us",
296 areatag,
297 rawlspid_print (lsp->lsp_header->lsp_id),
298 ntohl (seq_num), ntohs (checksum), ntohs (rem_lifetime));
299 zlog_debug ("ISIS-Snp (%s): is newer than ours seq 0x%08x, "
300 "cksum 0x%04x, lifetime %us",
301 areatag,
302 ntohl (lsp->lsp_header->seq_num),
303 ntohs (lsp->lsp_header->checksum),
304 ntohs (lsp->lsp_header->rem_lifetime));
hassof390d2c2004-09-10 20:48:21 +0000305 }
306 return LSP_NEWER;
jardineb5d44e2003-12-23 08:09:43 +0000307 }
hassof390d2c2004-09-10 20:48:21 +0000308 if (isis->debugs & DEBUG_SNP_PACKETS)
309 {
hasso529d65b2004-12-24 00:14:50 +0000310 zlog_debug
Josh Bailey3f045a02012-03-24 08:35:20 -0700311 ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x, lifetime %us",
hassof390d2c2004-09-10 20:48:21 +0000312 areatag, rawlspid_print (lsp->lsp_header->lsp_id), ntohl (seq_num),
313 ntohs (checksum), ntohs (rem_lifetime));
hasso529d65b2004-12-24 00:14:50 +0000314 zlog_debug ("ISIS-Snp (%s): is older than ours seq 0x%08x,"
315 " cksum 0x%04x, lifetime %us", areatag,
316 ntohl (lsp->lsp_header->seq_num),
317 ntohs (lsp->lsp_header->checksum),
318 ntohs (lsp->lsp_header->rem_lifetime));
hassof390d2c2004-09-10 20:48:21 +0000319 }
jardineb5d44e2003-12-23 08:09:43 +0000320
321 return LSP_OLDER;
322}
323
Josh Bailey3f045a02012-03-24 08:35:20 -0700324static void
325lsp_auth_add (struct isis_lsp *lsp)
326{
327 struct isis_passwd *passwd;
328 unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
329
330 /*
331 * Add the authentication info if its present
332 */
333 (lsp->level == IS_LEVEL_1) ? (passwd = &lsp->area->area_passwd) :
334 (passwd = &lsp->area->domain_passwd);
335 switch (passwd->type)
336 {
337 /* Cleartext */
338 case ISIS_PASSWD_TYPE_CLEARTXT:
339 memcpy (&lsp->tlv_data.auth_info, passwd, sizeof (struct isis_passwd));
340 tlv_add_authinfo (passwd->type, passwd->len, passwd->passwd, lsp->pdu);
341 break;
342
343 /* HMAC MD5 */
344 case ISIS_PASSWD_TYPE_HMAC_MD5:
345 /* Remember where TLV is written so we can later
346 * overwrite the MD5 hash */
347 lsp->auth_tlv_offset = stream_get_endp (lsp->pdu);
348 memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
349 lsp->tlv_data.auth_info.type = ISIS_PASSWD_TYPE_HMAC_MD5;
350 lsp->tlv_data.auth_info.len = ISIS_AUTH_MD5_SIZE;
351 memcpy (&lsp->tlv_data.auth_info.passwd, hmac_md5_hash,
352 ISIS_AUTH_MD5_SIZE);
353 tlv_add_authinfo (passwd->type, ISIS_AUTH_MD5_SIZE, hmac_md5_hash,
354 lsp->pdu);
355 break;
356
357 default:
358 break;
359 }
360}
361
362static void
363lsp_auth_update (struct isis_lsp *lsp)
364{
365 struct isis_passwd *passwd;
366 unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
367 uint16_t checksum, rem_lifetime;
368
369 /* For HMAC MD5 we need to recompute the md5 hash and store it */
370 (lsp->level == IS_LEVEL_1) ? (passwd = &lsp->area->area_passwd) :
371 (passwd = &lsp->area->domain_passwd);
372 if (passwd->type != ISIS_PASSWD_TYPE_HMAC_MD5)
373 return;
374
375 /*
376 * In transient conditions (when net is configured where authentication
377 * config and lsp regenerate schedule is not yet run), there could be
378 * an own_lsp with auth_tlv_offset set to 0. In such a case, simply
379 * return, when lsp_regenerate is run, lsp will have auth tlv.
380 */
381 if (lsp->auth_tlv_offset == 0)
382 return;
383
384 /*
385 * RFC 5304 set auth value, checksum and remaining lifetime to zero
386 * before computation and reset to old values after computation.
387 */
388 checksum = lsp->lsp_header->checksum;
389 rem_lifetime = lsp->lsp_header->rem_lifetime;
390 lsp->lsp_header->checksum = 0;
391 lsp->lsp_header->rem_lifetime = 0;
392 /* Set the authentication value as well to zero */
393 memset (STREAM_DATA (lsp->pdu) + lsp->auth_tlv_offset + 3,
394 0, ISIS_AUTH_MD5_SIZE);
395 /* Compute autentication value */
396 hmac_md5 (STREAM_DATA (lsp->pdu), stream_get_endp(lsp->pdu),
397 (unsigned char *) &passwd->passwd, passwd->len,
David Lamparter21401f32015-03-03 08:55:26 +0100398 (unsigned char *) &hmac_md5_hash);
Josh Bailey3f045a02012-03-24 08:35:20 -0700399 /* Copy the hash into the stream */
400 memcpy (STREAM_DATA (lsp->pdu) + lsp->auth_tlv_offset + 3,
401 hmac_md5_hash, ISIS_AUTH_MD5_SIZE);
402 memcpy (&lsp->tlv_data.auth_info.passwd, hmac_md5_hash,
403 ISIS_AUTH_MD5_SIZE);
404 /* Copy back the checksum and remaining lifetime */
405 lsp->lsp_header->checksum = checksum;
406 lsp->lsp_header->rem_lifetime = rem_lifetime;
407}
408
hassof390d2c2004-09-10 20:48:21 +0000409void
jardineb5d44e2003-12-23 08:09:43 +0000410lsp_inc_seqnum (struct isis_lsp *lsp, u_int32_t seq_num)
411{
412 u_int32_t newseq;
hassof390d2c2004-09-10 20:48:21 +0000413
jardineb5d44e2003-12-23 08:09:43 +0000414 if (seq_num == 0 || ntohl (lsp->lsp_header->seq_num) > seq_num)
415 newseq = ntohl (lsp->lsp_header->seq_num) + 1;
416 else
Josh Bailey3f045a02012-03-24 08:35:20 -0700417 newseq = seq_num + 1;
hassof390d2c2004-09-10 20:48:21 +0000418
jardineb5d44e2003-12-23 08:09:43 +0000419 lsp->lsp_header->seq_num = htonl (newseq);
Josh Bailey3f045a02012-03-24 08:35:20 -0700420
421 /* Recompute authentication and checksum information */
422 lsp_auth_update (lsp);
423 /* ISO 10589 - 7.3.11 Generation of the checksum
424 * The checksum shall be computed over all fields in the LSP which appear
425 * after the Remaining Lifetime field. This field (and those appearing
426 * before it) are excluded so that the LSP may be aged by systems without
427 * requiring recomputation.
428 */
429 fletcher_checksum(STREAM_DATA (lsp->pdu) + 12,
430 ntohs (lsp->lsp_header->pdu_len) - 12, 12);
431
432 isis_spf_schedule (lsp->area, lsp->level);
433#ifdef HAVE_IPV6
434 isis_spf_schedule6 (lsp->area, lsp->level);
435#endif
jardineb5d44e2003-12-23 08:09:43 +0000436
437 return;
438}
439
440/*
441 * Genetates checksum for LSP and its frags
442 */
hasso92365882005-01-18 13:53:33 +0000443static void
jardineb5d44e2003-12-23 08:09:43 +0000444lsp_seqnum_update (struct isis_lsp *lsp0)
445{
446 struct isis_lsp *lsp;
hasso3fdb2dd2005-09-28 18:45:54 +0000447 struct listnode *node;
hassof390d2c2004-09-10 20:48:21 +0000448
jardineb5d44e2003-12-23 08:09:43 +0000449 lsp_inc_seqnum (lsp0, 0);
450
451 if (!lsp0->lspu.frags)
452 return;
453
hasso3fdb2dd2005-09-28 18:45:54 +0000454 for (ALL_LIST_ELEMENTS_RO (lsp0->lspu.frags, node, lsp))
paul1eb8ef22005-04-07 07:30:20 +0000455 lsp_inc_seqnum (lsp, 0);
hassof390d2c2004-09-10 20:48:21 +0000456
jardineb5d44e2003-12-23 08:09:43 +0000457 return;
458}
459
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -0700460static u_int8_t
Amritha Nambiarc8ee9402015-08-24 16:40:14 -0700461lsp_bits_generate (int level, int overload_bit, int attached_bit)
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -0700462{
463 u_int8_t lsp_bits = 0;
464 if (level == IS_LEVEL_1)
465 lsp_bits = IS_LEVEL_1;
466 else
467 lsp_bits = IS_LEVEL_1_AND_2;
468 if (overload_bit)
469 lsp_bits |= overload_bit;
Amritha Nambiarc8ee9402015-08-24 16:40:14 -0700470 if (attached_bit)
471 lsp_bits |= attached_bit;
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -0700472 return lsp_bits;
473}
474
hasso92365882005-01-18 13:53:33 +0000475static void
hassof390d2c2004-09-10 20:48:21 +0000476lsp_update_data (struct isis_lsp *lsp, struct stream *stream,
Josh Bailey3f045a02012-03-24 08:35:20 -0700477 struct isis_area *area, int level)
jardineb5d44e2003-12-23 08:09:43 +0000478{
hassof390d2c2004-09-10 20:48:21 +0000479 uint32_t expected = 0, found;
jardineb5d44e2003-12-23 08:09:43 +0000480 int retval;
hassof390d2c2004-09-10 20:48:21 +0000481
Josh Bailey3f045a02012-03-24 08:35:20 -0700482 /* free the old lsp data */
483 lsp_clear_data (lsp);
484
jardineb5d44e2003-12-23 08:09:43 +0000485 /* copying only the relevant part of our stream */
Josh Bailey3f045a02012-03-24 08:35:20 -0700486 if (lsp->pdu != NULL)
487 stream_free (lsp->pdu);
paul15935e92005-05-03 09:27:23 +0000488 lsp->pdu = stream_dup (stream);
Josh Bailey3f045a02012-03-24 08:35:20 -0700489
jardineb5d44e2003-12-23 08:09:43 +0000490 /* setting pointers to the correct place */
hassof390d2c2004-09-10 20:48:21 +0000491 lsp->isis_header = (struct isis_fixed_hdr *) (STREAM_DATA (lsp->pdu));
492 lsp->lsp_header = (struct isis_link_state_hdr *) (STREAM_DATA (lsp->pdu) +
493 ISIS_FIXED_HDR_LEN);
Josh Bailey3f045a02012-03-24 08:35:20 -0700494 lsp->area = area;
495 lsp->level = level;
jardineb5d44e2003-12-23 08:09:43 +0000496 lsp->age_out = ZERO_AGE_LIFETIME;
hassof390d2c2004-09-10 20:48:21 +0000497 lsp->installed = time (NULL);
jardineb5d44e2003-12-23 08:09:43 +0000498 /*
499 * Get LSP data i.e. TLVs
500 */
501 expected |= TLVFLAG_AUTH_INFO;
502 expected |= TLVFLAG_AREA_ADDRS;
503 expected |= TLVFLAG_IS_NEIGHS;
jardineb5d44e2003-12-23 08:09:43 +0000504 expected |= TLVFLAG_NLPID;
505 if (area->dynhostname)
506 expected |= TLVFLAG_DYN_HOSTNAME;
hassof390d2c2004-09-10 20:48:21 +0000507 if (area->newmetric)
508 {
509 expected |= TLVFLAG_TE_IS_NEIGHS;
510 expected |= TLVFLAG_TE_IPV4_REACHABILITY;
511 expected |= TLVFLAG_TE_ROUTER_ID;
512 }
jardineb5d44e2003-12-23 08:09:43 +0000513 expected |= TLVFLAG_IPV4_ADDR;
514 expected |= TLVFLAG_IPV4_INT_REACHABILITY;
515 expected |= TLVFLAG_IPV4_EXT_REACHABILITY;
516#ifdef HAVE_IPV6
517 expected |= TLVFLAG_IPV6_ADDR;
518 expected |= TLVFLAG_IPV6_REACHABILITY;
519#endif /* HAVE_IPV6 */
520
Josh Bailey3f045a02012-03-24 08:35:20 -0700521 retval = parse_tlvs (area->area_tag, STREAM_DATA (lsp->pdu) +
522 ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN,
523 ntohs (lsp->lsp_header->pdu_len) -
524 ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN,
525 &expected, &found, &lsp->tlv_data,
526 NULL);
527 if (retval != ISIS_OK)
hassof390d2c2004-09-10 20:48:21 +0000528 {
Josh Bailey3f045a02012-03-24 08:35:20 -0700529 zlog_warn ("Could not parse LSP");
530 return;
531 }
532
533 if ((found & TLVFLAG_DYN_HOSTNAME) && (area->dynhostname))
534 {
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -0700535 isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname,
536 (lsp->lsp_header->lsp_bits & LSPBIT_IST) ==
537 IS_LEVEL_1_AND_2 ? IS_LEVEL_2 : IS_LEVEL_1);
hassof390d2c2004-09-10 20:48:21 +0000538 }
jardineb5d44e2003-12-23 08:09:43 +0000539
Josh Bailey3f045a02012-03-24 08:35:20 -0700540 return;
jardineb5d44e2003-12-23 08:09:43 +0000541}
542
543void
Josh Bailey3f045a02012-03-24 08:35:20 -0700544lsp_update (struct isis_lsp *lsp, struct stream *stream,
545 struct isis_area *area, int level)
jardineb5d44e2003-12-23 08:09:43 +0000546{
hasso4eda93a2005-09-18 17:51:02 +0000547 dnode_t *dnode = NULL;
hassoa96d8d12005-09-16 14:44:23 +0000548
Josh Bailey3f045a02012-03-24 08:35:20 -0700549 /* Remove old LSP from database. This is required since the
550 * lsp_update_data will free the lsp->pdu (which has the key, lsp_id)
551 * and will update it with the new data in the stream. */
hasso4eda93a2005-09-18 17:51:02 +0000552 dnode = dict_lookup (area->lspdb[level - 1], lsp->lsp_header->lsp_id);
553 if (dnode)
554 dnode_destroy (dict_delete (area->lspdb[level - 1], dnode));
hassoa96d8d12005-09-16 14:44:23 +0000555
jardineb5d44e2003-12-23 08:09:43 +0000556 /* rebuild the lsp data */
Josh Bailey3f045a02012-03-24 08:35:20 -0700557 lsp_update_data (lsp, stream, area, level);
jardineb5d44e2003-12-23 08:09:43 +0000558
Josh Bailey3f045a02012-03-24 08:35:20 -0700559 /* insert the lsp back into the database */
560 lsp_insert (lsp, area->lspdb[level - 1]);
jardineb5d44e2003-12-23 08:09:43 +0000561}
562
jardineb5d44e2003-12-23 08:09:43 +0000563/* creation of LSP directly from what we received */
564struct isis_lsp *
hassof390d2c2004-09-10 20:48:21 +0000565lsp_new_from_stream_ptr (struct stream *stream,
566 u_int16_t pdu_len, struct isis_lsp *lsp0,
Josh Bailey3f045a02012-03-24 08:35:20 -0700567 struct isis_area *area, int level)
jardineb5d44e2003-12-23 08:09:43 +0000568{
569 struct isis_lsp *lsp;
570
hassoaac372f2005-09-01 17:52:33 +0000571 lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp));
Josh Bailey3f045a02012-03-24 08:35:20 -0700572 lsp_update_data (lsp, stream, area, level);
hassof390d2c2004-09-10 20:48:21 +0000573
574 if (lsp0 == NULL)
575 {
576 /*
577 * zero lsp -> create the list for fragments
578 */
579 lsp->lspu.frags = list_new ();
580 }
581 else
582 {
583 /*
584 * a fragment -> set the backpointer and add this to zero lsps frag list
585 */
586 lsp->lspu.zero_lsp = lsp0;
587 listnode_add (lsp0->lspu.frags, lsp);
588 }
589
jardineb5d44e2003-12-23 08:09:43 +0000590 return lsp;
591}
592
593struct isis_lsp *
Christian Frankef1fc1db2015-11-10 18:43:31 +0100594lsp_new(struct isis_area *area, u_char * lsp_id,
595 u_int16_t rem_lifetime, u_int32_t seq_num,
596 u_int8_t lsp_bits, u_int16_t checksum, int level)
jardineb5d44e2003-12-23 08:09:43 +0000597{
598 struct isis_lsp *lsp;
599
hassoaac372f2005-09-01 17:52:33 +0000600 lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp));
Christian Frankef1fc1db2015-11-10 18:43:31 +0100601 lsp->area = area;
Christian Franke390f16e2015-11-10 18:04:44 +0100602
Christian Frankef1fc1db2015-11-10 18:43:31 +0100603 lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu);
jardineb5d44e2003-12-23 08:09:43 +0000604 if (LSP_FRAGMENT (lsp_id) == 0)
605 lsp->lspu.frags = list_new ();
hassof390d2c2004-09-10 20:48:21 +0000606 lsp->isis_header = (struct isis_fixed_hdr *) (STREAM_DATA (lsp->pdu));
607 lsp->lsp_header = (struct isis_link_state_hdr *)
608 (STREAM_DATA (lsp->pdu) + ISIS_FIXED_HDR_LEN);
609
jardineb5d44e2003-12-23 08:09:43 +0000610 /* at first we fill the FIXED HEADER */
Josh Bailey3f045a02012-03-24 08:35:20 -0700611 (level == IS_LEVEL_1) ? fill_fixed_hdr (lsp->isis_header, L1_LINK_STATE) :
hassof390d2c2004-09-10 20:48:21 +0000612 fill_fixed_hdr (lsp->isis_header, L2_LINK_STATE);
613
jardineb5d44e2003-12-23 08:09:43 +0000614 /* now for the LSP HEADER */
615 /* Minimal LSP PDU size */
hassof390d2c2004-09-10 20:48:21 +0000616 lsp->lsp_header->pdu_len = htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
jardineb5d44e2003-12-23 08:09:43 +0000617 memcpy (lsp->lsp_header->lsp_id, lsp_id, ISIS_SYS_ID_LEN + 2);
hassof390d2c2004-09-10 20:48:21 +0000618 lsp->lsp_header->checksum = checksum; /* Provided in network order */
jardineb5d44e2003-12-23 08:09:43 +0000619 lsp->lsp_header->seq_num = htonl (seq_num);
620 lsp->lsp_header->rem_lifetime = htons (rem_lifetime);
621 lsp->lsp_header->lsp_bits = lsp_bits;
622 lsp->level = level;
623 lsp->age_out = ZERO_AGE_LIFETIME;
624
paul9985f832005-02-09 15:51:56 +0000625 stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
jardineb5d44e2003-12-23 08:09:43 +0000626
hassoc89c05d2005-09-04 21:36:36 +0000627 if (isis->debugs & DEBUG_EVENTS)
Josh Bailey3f045a02012-03-24 08:35:20 -0700628 zlog_debug ("New LSP with ID %s-%02x-%02x len %d seqnum %08x",
hassoc89c05d2005-09-04 21:36:36 +0000629 sysid_print (lsp_id), LSP_PSEUDO_ID (lsp->lsp_header->lsp_id),
630 LSP_FRAGMENT (lsp->lsp_header->lsp_id),
Josh Bailey3f045a02012-03-24 08:35:20 -0700631 ntohl (lsp->lsp_header->pdu_len),
hassoc89c05d2005-09-04 21:36:36 +0000632 ntohl (lsp->lsp_header->seq_num));
jardineb5d44e2003-12-23 08:09:43 +0000633
634 return lsp;
635}
636
637void
hassof390d2c2004-09-10 20:48:21 +0000638lsp_insert (struct isis_lsp *lsp, dict_t * lspdb)
jardineb5d44e2003-12-23 08:09:43 +0000639{
640 dict_alloc_insert (lspdb, lsp->lsp_header->lsp_id, lsp);
Josh Bailey3f045a02012-03-24 08:35:20 -0700641 if (lsp->lsp_header->seq_num != 0)
642 {
643 isis_spf_schedule (lsp->area, lsp->level);
644#ifdef HAVE_IPV6
645 isis_spf_schedule6 (lsp->area, lsp->level);
646#endif
647 }
jardineb5d44e2003-12-23 08:09:43 +0000648}
649
650/*
651 * Build a list of LSPs with non-zero ht bounded by start and stop ids
652 */
hassof390d2c2004-09-10 20:48:21 +0000653void
654lsp_build_list_nonzero_ht (u_char * start_id, u_char * stop_id,
655 struct list *list, dict_t * lspdb)
jardineb5d44e2003-12-23 08:09:43 +0000656{
657 dnode_t *first, *last, *curr;
658
659 first = dict_lower_bound (lspdb, start_id);
660 if (!first)
661 return;
hassof390d2c2004-09-10 20:48:21 +0000662
jardineb5d44e2003-12-23 08:09:43 +0000663 last = dict_upper_bound (lspdb, stop_id);
hassof390d2c2004-09-10 20:48:21 +0000664
jardineb5d44e2003-12-23 08:09:43 +0000665 curr = first;
hassof390d2c2004-09-10 20:48:21 +0000666
667 if (((struct isis_lsp *) (curr->dict_data))->lsp_header->rem_lifetime)
jardineb5d44e2003-12-23 08:09:43 +0000668 listnode_add (list, first->dict_data);
669
hassof390d2c2004-09-10 20:48:21 +0000670 while (curr)
671 {
672 curr = dict_next (lspdb, curr);
673 if (curr &&
674 ((struct isis_lsp *) (curr->dict_data))->lsp_header->rem_lifetime)
675 listnode_add (list, curr->dict_data);
676 if (curr == last)
677 break;
678 }
679
jardineb5d44e2003-12-23 08:09:43 +0000680 return;
681}
682
683/*
Josh Bailey3f045a02012-03-24 08:35:20 -0700684 * Build a list of num_lsps LSPs bounded by start_id and stop_id.
jardineb5d44e2003-12-23 08:09:43 +0000685 */
hassof390d2c2004-09-10 20:48:21 +0000686void
Josh Bailey3f045a02012-03-24 08:35:20 -0700687lsp_build_list (u_char * start_id, u_char * stop_id, u_char num_lsps,
hassof390d2c2004-09-10 20:48:21 +0000688 struct list *list, dict_t * lspdb)
jardineb5d44e2003-12-23 08:09:43 +0000689{
Josh Bailey3f045a02012-03-24 08:35:20 -0700690 u_char count;
jardineb5d44e2003-12-23 08:09:43 +0000691 dnode_t *first, *last, *curr;
692
693 first = dict_lower_bound (lspdb, start_id);
694 if (!first)
695 return;
hassof390d2c2004-09-10 20:48:21 +0000696
jardineb5d44e2003-12-23 08:09:43 +0000697 last = dict_upper_bound (lspdb, stop_id);
hassof390d2c2004-09-10 20:48:21 +0000698
jardineb5d44e2003-12-23 08:09:43 +0000699 curr = first;
hassof390d2c2004-09-10 20:48:21 +0000700
jardineb5d44e2003-12-23 08:09:43 +0000701 listnode_add (list, first->dict_data);
Josh Bailey3f045a02012-03-24 08:35:20 -0700702 count = 1;
jardineb5d44e2003-12-23 08:09:43 +0000703
hassof390d2c2004-09-10 20:48:21 +0000704 while (curr)
705 {
706 curr = dict_next (lspdb, curr);
707 if (curr)
Josh Bailey3f045a02012-03-24 08:35:20 -0700708 {
709 listnode_add (list, curr->dict_data);
710 count++;
711 }
712 if (count == num_lsps || curr == last)
713 break;
hassof390d2c2004-09-10 20:48:21 +0000714 }
715
jardineb5d44e2003-12-23 08:09:43 +0000716 return;
717}
718
719/*
720 * Build a list of LSPs with SSN flag set for the given circuit
721 */
722void
Josh Bailey3f045a02012-03-24 08:35:20 -0700723lsp_build_list_ssn (struct isis_circuit *circuit, u_char num_lsps,
724 struct list *list, dict_t * lspdb)
jardineb5d44e2003-12-23 08:09:43 +0000725{
726 dnode_t *dnode, *next;
727 struct isis_lsp *lsp;
Josh Bailey3f045a02012-03-24 08:35:20 -0700728 u_char count = 0;
hassof390d2c2004-09-10 20:48:21 +0000729
jardineb5d44e2003-12-23 08:09:43 +0000730 dnode = dict_first (lspdb);
hassof390d2c2004-09-10 20:48:21 +0000731 while (dnode != NULL)
732 {
733 next = dict_next (lspdb, dnode);
734 lsp = dnode_get (dnode);
735 if (ISIS_CHECK_FLAG (lsp->SSNflags, circuit))
Josh Bailey3f045a02012-03-24 08:35:20 -0700736 {
737 listnode_add (list, lsp);
738 ++count;
739 }
740 if (count == num_lsps)
741 break;
hassof390d2c2004-09-10 20:48:21 +0000742 dnode = next;
743 }
744
jardineb5d44e2003-12-23 08:09:43 +0000745 return;
746}
747
hasso92365882005-01-18 13:53:33 +0000748static void
jardineb5d44e2003-12-23 08:09:43 +0000749lsp_set_time (struct isis_lsp *lsp)
750{
751 assert (lsp);
hassof390d2c2004-09-10 20:48:21 +0000752
753 if (lsp->lsp_header->rem_lifetime == 0)
754 {
Josh Bailey3f045a02012-03-24 08:35:20 -0700755 if (lsp->age_out > 0)
756 lsp->age_out--;
hassof390d2c2004-09-10 20:48:21 +0000757 return;
758 }
jardineb5d44e2003-12-23 08:09:43 +0000759
hassof390d2c2004-09-10 20:48:21 +0000760 lsp->lsp_header->rem_lifetime =
jardineb5d44e2003-12-23 08:09:43 +0000761 htons (ntohs (lsp->lsp_header->rem_lifetime) - 1);
762}
763
hasso92365882005-01-18 13:53:33 +0000764static void
hassof390d2c2004-09-10 20:48:21 +0000765lspid_print (u_char * lsp_id, u_char * trg, char dynhost, char frag)
jardineb5d44e2003-12-23 08:09:43 +0000766{
767 struct isis_dynhn *dyn = NULL;
hassof390d2c2004-09-10 20:48:21 +0000768 u_char id[SYSID_STRLEN];
jardineb5d44e2003-12-23 08:09:43 +0000769
770 if (dynhost)
771 dyn = dynhn_find_by_id (lsp_id);
772 else
773 dyn = NULL;
774
775 if (dyn)
Josh Bailey3f045a02012-03-24 08:35:20 -0700776 sprintf ((char *)id, "%.14s", dyn->name.name);
777 else if (!memcmp (isis->sysid, lsp_id, ISIS_SYS_ID_LEN) && dynhost)
778 sprintf ((char *)id, "%.14s", unix_hostname ());
jardineb5d44e2003-12-23 08:09:43 +0000779 else
hassof390d2c2004-09-10 20:48:21 +0000780 memcpy (id, sysid_print (lsp_id), 15);
hassof390d2c2004-09-10 20:48:21 +0000781 if (frag)
hassof7c43dc2004-09-26 16:24:14 +0000782 sprintf ((char *)trg, "%s.%02x-%02x", id, LSP_PSEUDO_ID (lsp_id),
hassof390d2c2004-09-10 20:48:21 +0000783 LSP_FRAGMENT (lsp_id));
784 else
hassof7c43dc2004-09-26 16:24:14 +0000785 sprintf ((char *)trg, "%s.%02x", id, LSP_PSEUDO_ID (lsp_id));
jardineb5d44e2003-12-23 08:09:43 +0000786}
787
hassof390d2c2004-09-10 20:48:21 +0000788/* Convert the lsp attribute bits to attribute string */
hasso1cd80842004-10-07 20:07:40 +0000789const char *
hassof390d2c2004-09-10 20:48:21 +0000790lsp_bits2string (u_char * lsp_bits)
791{
792 char *pos = lsp_bits_string;
jardineb5d44e2003-12-23 08:09:43 +0000793
hassof390d2c2004-09-10 20:48:21 +0000794 if (!*lsp_bits)
jardineb5d44e2003-12-23 08:09:43 +0000795 return " none";
796
797 /* we only focus on the default metric */
798 pos += sprintf (pos, "%d/",
hassof390d2c2004-09-10 20:48:21 +0000799 ISIS_MASK_LSP_ATT_DEFAULT_BIT (*lsp_bits) ? 1 : 0);
jardineb5d44e2003-12-23 08:09:43 +0000800
801 pos += sprintf (pos, "%d/",
hassof390d2c2004-09-10 20:48:21 +0000802 ISIS_MASK_LSP_PARTITION_BIT (*lsp_bits) ? 1 : 0);
jardineb5d44e2003-12-23 08:09:43 +0000803
hassof390d2c2004-09-10 20:48:21 +0000804 pos += sprintf (pos, "%d", ISIS_MASK_LSP_OL_BIT (*lsp_bits) ? 1 : 0);
805
jardineb5d44e2003-12-23 08:09:43 +0000806 *(pos) = '\0';
jardineb5d44e2003-12-23 08:09:43 +0000807
hassof390d2c2004-09-10 20:48:21 +0000808 return lsp_bits_string;
jardineb5d44e2003-12-23 08:09:43 +0000809}
810
811/* this function prints the lsp on show isis database */
Josh Bailey3f045a02012-03-24 08:35:20 -0700812void
813lsp_print (struct isis_lsp *lsp, struct vty *vty, char dynhost)
jardineb5d44e2003-12-23 08:09:43 +0000814{
jardineb5d44e2003-12-23 08:09:43 +0000815 u_char LSPid[255];
Josh Bailey3f045a02012-03-24 08:35:20 -0700816 char age_out[8];
jardineb5d44e2003-12-23 08:09:43 +0000817
818 lspid_print (lsp->lsp_header->lsp_id, LSPid, dynhost, 1);
Josh Bailey3f045a02012-03-24 08:35:20 -0700819 vty_out (vty, "%-21s%c ", LSPid, lsp->own_lsp ? '*' : ' ');
820 vty_out (vty, "%5u ", ntohs (lsp->lsp_header->pdu_len));
821 vty_out (vty, "0x%08x ", ntohl (lsp->lsp_header->seq_num));
822 vty_out (vty, "0x%04x ", ntohs (lsp->lsp_header->checksum));
hassof390d2c2004-09-10 20:48:21 +0000823 if (ntohs (lsp->lsp_header->rem_lifetime) == 0)
Josh Bailey3f045a02012-03-24 08:35:20 -0700824 {
825 snprintf (age_out, 8, "(%u)", lsp->age_out);
826 age_out[7] = '\0';
827 vty_out (vty, "%7s ", age_out);
828 }
jardineb5d44e2003-12-23 08:09:43 +0000829 else
Josh Bailey3f045a02012-03-24 08:35:20 -0700830 vty_out (vty, " %5u ", ntohs (lsp->lsp_header->rem_lifetime));
831 vty_out (vty, "%s%s",
832 lsp_bits2string (&lsp->lsp_header->lsp_bits), VTY_NEWLINE);
jardineb5d44e2003-12-23 08:09:43 +0000833}
834
Josh Bailey3f045a02012-03-24 08:35:20 -0700835void
836lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost)
jardineb5d44e2003-12-23 08:09:43 +0000837{
jardineb5d44e2003-12-23 08:09:43 +0000838 struct area_addr *area_addr;
hassof390d2c2004-09-10 20:48:21 +0000839 int i;
hasso3fdb2dd2005-09-28 18:45:54 +0000840 struct listnode *lnode;
jardineb5d44e2003-12-23 08:09:43 +0000841 struct is_neigh *is_neigh;
842 struct te_is_neigh *te_is_neigh;
843 struct ipv4_reachability *ipv4_reach;
844 struct in_addr *ipv4_addr;
845 struct te_ipv4_reachability *te_ipv4_reach;
846#ifdef HAVE_IPV6
847 struct ipv6_reachability *ipv6_reach;
848 struct in6_addr in6;
Paul Jakma41b36e92006-12-08 01:09:50 +0000849 u_char buff[BUFSIZ];
jardineb5d44e2003-12-23 08:09:43 +0000850#endif
851 u_char LSPid[255];
852 u_char hostname[255];
jardineb5d44e2003-12-23 08:09:43 +0000853 u_char ipv4_reach_prefix[20];
854 u_char ipv4_reach_mask[20];
855 u_char ipv4_address[20];
856
857 lspid_print (lsp->lsp_header->lsp_id, LSPid, dynhost, 1);
Josh Bailey3f045a02012-03-24 08:35:20 -0700858 lsp_print (lsp, vty, dynhost);
jardineb5d44e2003-12-23 08:09:43 +0000859
860 /* for all area address */
hassof390d2c2004-09-10 20:48:21 +0000861 if (lsp->tlv_data.area_addrs)
hasso3fdb2dd2005-09-28 18:45:54 +0000862 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.area_addrs, lnode, area_addr))
hassof390d2c2004-09-10 20:48:21 +0000863 {
hasso1cd80842004-10-07 20:07:40 +0000864 vty_out (vty, " Area Address: %s%s",
hassof390d2c2004-09-10 20:48:21 +0000865 isonet_print (area_addr->area_addr, area_addr->addr_len),
866 VTY_NEWLINE);
867 }
paul1eb8ef22005-04-07 07:30:20 +0000868
jardineb5d44e2003-12-23 08:09:43 +0000869 /* for the nlpid tlv */
hassof390d2c2004-09-10 20:48:21 +0000870 if (lsp->tlv_data.nlpids)
871 {
872 for (i = 0; i < lsp->tlv_data.nlpids->count; i++)
873 {
874 switch (lsp->tlv_data.nlpids->nlpids[i])
875 {
876 case NLPID_IP:
877 case NLPID_IPV6:
Josh Bailey3f045a02012-03-24 08:35:20 -0700878 vty_out (vty, " NLPID : 0x%X%s",
hassof390d2c2004-09-10 20:48:21 +0000879 lsp->tlv_data.nlpids->nlpids[i], VTY_NEWLINE);
880 break;
881 default:
Josh Bailey3f045a02012-03-24 08:35:20 -0700882 vty_out (vty, " NLPID : %s%s", "unknown", VTY_NEWLINE);
hassof390d2c2004-09-10 20:48:21 +0000883 break;
884 }
885 }
886 }
jardineb5d44e2003-12-23 08:09:43 +0000887
888 /* for the hostname tlv */
hassof390d2c2004-09-10 20:48:21 +0000889 if (lsp->tlv_data.hostname)
890 {
Josh Bailey3f045a02012-03-24 08:35:20 -0700891 bzero (hostname, sizeof (hostname));
hassof390d2c2004-09-10 20:48:21 +0000892 memcpy (hostname, lsp->tlv_data.hostname->name,
893 lsp->tlv_data.hostname->namelen);
Josh Bailey3f045a02012-03-24 08:35:20 -0700894 vty_out (vty, " Hostname : %s%s", hostname, VTY_NEWLINE);
jardineb5d44e2003-12-23 08:09:43 +0000895 }
hassof390d2c2004-09-10 20:48:21 +0000896
Josh Bailey3f045a02012-03-24 08:35:20 -0700897 /* authentication tlv */
898 if (lsp->tlv_data.auth_info.type != ISIS_PASSWD_TYPE_UNUSED)
899 {
900 if (lsp->tlv_data.auth_info.type == ISIS_PASSWD_TYPE_HMAC_MD5)
901 vty_out (vty, " Auth type : md5%s", VTY_NEWLINE);
902 else if (lsp->tlv_data.auth_info.type == ISIS_PASSWD_TYPE_CLEARTXT)
903 vty_out (vty, " Auth type : clear text%s", VTY_NEWLINE);
904 }
hassof390d2c2004-09-10 20:48:21 +0000905
hasso1cd80842004-10-07 20:07:40 +0000906 /* TE router id */
907 if (lsp->tlv_data.router_id)
908 {
909 memcpy (ipv4_address, inet_ntoa (lsp->tlv_data.router_id->id),
910 sizeof (ipv4_address));
Josh Bailey3f045a02012-03-24 08:35:20 -0700911 vty_out (vty, " Router ID : %s%s", ipv4_address, VTY_NEWLINE);
hasso1cd80842004-10-07 20:07:40 +0000912 }
913
Josh Bailey3f045a02012-03-24 08:35:20 -0700914 if (lsp->tlv_data.ipv4_addrs)
915 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_addrs, lnode, ipv4_addr))
916 {
917 memcpy (ipv4_address, inet_ntoa (*ipv4_addr), sizeof (ipv4_address));
918 vty_out (vty, " IPv4 Address: %s%s", ipv4_address, VTY_NEWLINE);
919 }
920
hasso1cd80842004-10-07 20:07:40 +0000921 /* for the IS neighbor tlv */
922 if (lsp->tlv_data.is_neighs)
hasso3fdb2dd2005-09-28 18:45:54 +0000923 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, lnode, is_neigh))
hasso1cd80842004-10-07 20:07:40 +0000924 {
925 lspid_print (is_neigh->neigh_id, LSPid, dynhost, 0);
Josh Bailey3f045a02012-03-24 08:35:20 -0700926 vty_out (vty, " Metric : %-8d IS : %s%s",
hasso1cd80842004-10-07 20:07:40 +0000927 is_neigh->metrics.metric_default, LSPid, VTY_NEWLINE);
928 }
hasso1cd80842004-10-07 20:07:40 +0000929
jardineb5d44e2003-12-23 08:09:43 +0000930 /* for the internal reachable tlv */
931 if (lsp->tlv_data.ipv4_int_reachs)
hasso3fdb2dd2005-09-28 18:45:54 +0000932 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_int_reachs, lnode,
933 ipv4_reach))
hassof390d2c2004-09-10 20:48:21 +0000934 {
935 memcpy (ipv4_reach_prefix, inet_ntoa (ipv4_reach->prefix),
936 sizeof (ipv4_reach_prefix));
937 memcpy (ipv4_reach_mask, inet_ntoa (ipv4_reach->mask),
938 sizeof (ipv4_reach_mask));
Josh Bailey3f045a02012-03-24 08:35:20 -0700939 vty_out (vty, " Metric : %-8d IPv4-Internal : %s %s%s",
hassof390d2c2004-09-10 20:48:21 +0000940 ipv4_reach->metrics.metric_default, ipv4_reach_prefix,
941 ipv4_reach_mask, VTY_NEWLINE);
942 }
hasso2097cd82003-12-23 11:51:08 +0000943
944 /* for the external reachable tlv */
945 if (lsp->tlv_data.ipv4_ext_reachs)
hasso3fdb2dd2005-09-28 18:45:54 +0000946 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_ext_reachs, lnode,
947 ipv4_reach))
hassof390d2c2004-09-10 20:48:21 +0000948 {
949 memcpy (ipv4_reach_prefix, inet_ntoa (ipv4_reach->prefix),
950 sizeof (ipv4_reach_prefix));
951 memcpy (ipv4_reach_mask, inet_ntoa (ipv4_reach->mask),
952 sizeof (ipv4_reach_mask));
Josh Bailey3f045a02012-03-24 08:35:20 -0700953 vty_out (vty, " Metric : %-8d IPv4-External : %s %s%s",
hassof390d2c2004-09-10 20:48:21 +0000954 ipv4_reach->metrics.metric_default, ipv4_reach_prefix,
955 ipv4_reach_mask, VTY_NEWLINE);
956 }
paul1eb8ef22005-04-07 07:30:20 +0000957
hasso2097cd82003-12-23 11:51:08 +0000958 /* IPv6 tlv */
959#ifdef HAVE_IPV6
960 if (lsp->tlv_data.ipv6_reachs)
hasso3fdb2dd2005-09-28 18:45:54 +0000961 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv6_reachs, lnode, ipv6_reach))
hassof390d2c2004-09-10 20:48:21 +0000962 {
963 memset (&in6, 0, sizeof (in6));
964 memcpy (in6.s6_addr, ipv6_reach->prefix,
965 PSIZE (ipv6_reach->prefix_len));
hassof7c43dc2004-09-26 16:24:14 +0000966 inet_ntop (AF_INET6, &in6, (char *)buff, BUFSIZ);
David Lamparter6db3ef62015-03-03 09:07:43 +0100967 if ((ipv6_reach->control_info &
hassof390d2c2004-09-10 20:48:21 +0000968 CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL)
Josh Bailey3f045a02012-03-24 08:35:20 -0700969 vty_out (vty, " Metric : %-8d IPv6-Internal : %s/%d%s",
hassof390d2c2004-09-10 20:48:21 +0000970 ntohl (ipv6_reach->metric),
971 buff, ipv6_reach->prefix_len, VTY_NEWLINE);
hasso2097cd82003-12-23 11:51:08 +0000972 else
Josh Bailey3f045a02012-03-24 08:35:20 -0700973 vty_out (vty, " Metric : %-8d IPv6-External : %s/%d%s",
hassof390d2c2004-09-10 20:48:21 +0000974 ntohl (ipv6_reach->metric),
975 buff, ipv6_reach->prefix_len, VTY_NEWLINE);
hasso2097cd82003-12-23 11:51:08 +0000976 }
977#endif
paul1eb8ef22005-04-07 07:30:20 +0000978
hasso1cd80842004-10-07 20:07:40 +0000979 /* TE IS neighbor tlv */
jardineb5d44e2003-12-23 08:09:43 +0000980 if (lsp->tlv_data.te_is_neighs)
hasso3fdb2dd2005-09-28 18:45:54 +0000981 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, lnode, te_is_neigh))
hassof390d2c2004-09-10 20:48:21 +0000982 {
hassof390d2c2004-09-10 20:48:21 +0000983 lspid_print (te_is_neigh->neigh_id, LSPid, dynhost, 0);
Josh Bailey3f045a02012-03-24 08:35:20 -0700984 vty_out (vty, " Metric : %-8d IS-Extended : %s%s",
985 GET_TE_METRIC(te_is_neigh), LSPid, VTY_NEWLINE);
hassof390d2c2004-09-10 20:48:21 +0000986 }
jardineb5d44e2003-12-23 08:09:43 +0000987
hasso1cd80842004-10-07 20:07:40 +0000988 /* TE IPv4 tlv */
jardineb5d44e2003-12-23 08:09:43 +0000989 if (lsp->tlv_data.te_ipv4_reachs)
hasso3fdb2dd2005-09-28 18:45:54 +0000990 for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_ipv4_reachs, lnode,
991 te_ipv4_reach))
hassof390d2c2004-09-10 20:48:21 +0000992 {
hasso1cd80842004-10-07 20:07:40 +0000993 /* FIXME: There should be better way to output this stuff. */
Josh Bailey3f045a02012-03-24 08:35:20 -0700994 vty_out (vty, " Metric : %-8d IPv4-Extended : %s/%d%s",
hasso1cd80842004-10-07 20:07:40 +0000995 ntohl (te_ipv4_reach->te_metric),
hassof390d2c2004-09-10 20:48:21 +0000996 inet_ntoa (newprefix2inaddr (&te_ipv4_reach->prefix_start,
997 te_ipv4_reach->control)),
hasso1cd80842004-10-07 20:07:40 +0000998 te_ipv4_reach->control & 0x3F, VTY_NEWLINE);
hassof390d2c2004-09-10 20:48:21 +0000999 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001000 vty_out (vty, "%s", VTY_NEWLINE);
jardineb5d44e2003-12-23 08:09:43 +00001001
hassof390d2c2004-09-10 20:48:21 +00001002 return;
jardineb5d44e2003-12-23 08:09:43 +00001003}
1004
1005/* print all the lsps info in the local lspdb */
hassof390d2c2004-09-10 20:48:21 +00001006int
1007lsp_print_all (struct vty *vty, dict_t * lspdb, char detail, char dynhost)
jardineb5d44e2003-12-23 08:09:43 +00001008{
1009
hassof390d2c2004-09-10 20:48:21 +00001010 dnode_t *node = dict_first (lspdb), *next;
jardineb5d44e2003-12-23 08:09:43 +00001011 int lsp_count = 0;
1012
hassof390d2c2004-09-10 20:48:21 +00001013 if (detail == ISIS_UI_LEVEL_BRIEF)
1014 {
1015 while (node != NULL)
1016 {
1017 /* I think it is unnecessary, so I comment it out */
1018 /* dict_contains (lspdb, node); */
1019 next = dict_next (lspdb, node);
Josh Bailey3f045a02012-03-24 08:35:20 -07001020 lsp_print (dnode_get (node), vty, dynhost);
hassof390d2c2004-09-10 20:48:21 +00001021 node = next;
1022 lsp_count++;
1023 }
jardineb5d44e2003-12-23 08:09:43 +00001024 }
hassof390d2c2004-09-10 20:48:21 +00001025 else if (detail == ISIS_UI_LEVEL_DETAIL)
1026 {
1027 while (node != NULL)
1028 {
1029 next = dict_next (lspdb, node);
Josh Bailey3f045a02012-03-24 08:35:20 -07001030 lsp_print_detail (dnode_get (node), vty, dynhost);
hassof390d2c2004-09-10 20:48:21 +00001031 node = next;
1032 lsp_count++;
1033 }
jardineb5d44e2003-12-23 08:09:43 +00001034 }
jardineb5d44e2003-12-23 08:09:43 +00001035
1036 return lsp_count;
1037}
1038
jardineb5d44e2003-12-23 08:09:43 +00001039#define FRAG_THOLD(S,T) \
Josh Bailey3f045a02012-03-24 08:35:20 -07001040 ((STREAM_SIZE(S)*T)/100)
jardineb5d44e2003-12-23 08:09:43 +00001041
1042/* stream*, area->lsp_frag_threshold, increment */
1043#define FRAG_NEEDED(S,T,I) \
1044 (STREAM_SIZE(S)-STREAM_REMAIN(S)+(I) > FRAG_THOLD(S,T))
1045
hassoaa4376e2005-09-26 17:39:48 +00001046/* FIXME: It shouldn't be necessary to pass tlvsize here, TLVs can have
1047 * variable length (TE TLVs, sub TLVs). */
hasso92365882005-01-18 13:53:33 +00001048static void
jardineb5d44e2003-12-23 08:09:43 +00001049lsp_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to,
hassof390d2c2004-09-10 20:48:21 +00001050 int tlvsize, int frag_thold,
1051 int tlv_build_func (struct list *, struct stream *))
jardineb5d44e2003-12-23 08:09:43 +00001052{
1053 int count, i;
hassof390d2c2004-09-10 20:48:21 +00001054
jardineb5d44e2003-12-23 08:09:43 +00001055 /* can we fit all ? */
hassof390d2c2004-09-10 20:48:21 +00001056 if (!FRAG_NEEDED (lsp->pdu, frag_thold, listcount (*from) * tlvsize + 2))
1057 {
1058 tlv_build_func (*from, lsp->pdu);
Josh Bailey3f045a02012-03-24 08:35:20 -07001059 if (listcount (*to) != 0)
1060 {
1061 struct listnode *node, *nextnode;
1062 void *elem;
1063
1064 for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem))
1065 {
1066 listnode_add (*to, elem);
1067 list_delete_node (*from, node);
1068 }
1069 }
1070 else
1071 {
1072 list_free (*to);
1073 *to = *from;
1074 *from = NULL;
1075 }
jardineb5d44e2003-12-23 08:09:43 +00001076 }
hassof390d2c2004-09-10 20:48:21 +00001077 else if (!FRAG_NEEDED (lsp->pdu, frag_thold, tlvsize + 2))
1078 {
1079 /* fit all we can */
1080 count = FRAG_THOLD (lsp->pdu, frag_thold) - 2 -
1081 (STREAM_SIZE (lsp->pdu) - STREAM_REMAIN (lsp->pdu));
Josh Bailey3f045a02012-03-24 08:35:20 -07001082 count = count / tlvsize;
1083 if (count > (int)listcount (*from))
1084 count = listcount (*from);
hassof390d2c2004-09-10 20:48:21 +00001085 for (i = 0; i < count; i++)
1086 {
paul1eb8ef22005-04-07 07:30:20 +00001087 listnode_add (*to, listgetdata (listhead (*from)));
1088 listnode_delete (*from, listgetdata (listhead (*from)));
hassof390d2c2004-09-10 20:48:21 +00001089 }
1090 tlv_build_func (*to, lsp->pdu);
1091 }
paul9985f832005-02-09 15:51:56 +00001092 lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
jardineb5d44e2003-12-23 08:09:43 +00001093 return;
1094}
1095
Josh Bailey3f045a02012-03-24 08:35:20 -07001096static u_int16_t
1097lsp_rem_lifetime (struct isis_area *area, int level)
1098{
1099 u_int16_t rem_lifetime;
1100
1101 /* Add jitter to configured LSP lifetime */
1102 rem_lifetime = isis_jitter (area->max_lsp_lifetime[level - 1],
1103 MAX_AGE_JITTER);
1104
1105 /* No jitter if the max refresh will be less than configure gen interval */
Christian Franke9dfcca62015-11-10 18:32:11 +01001106 /* N.B. this calucation is acceptable since rem_lifetime is in [332,65535] at
1107 * this point */
Josh Bailey3f045a02012-03-24 08:35:20 -07001108 if (area->lsp_gen_interval[level - 1] > (rem_lifetime - 300))
1109 rem_lifetime = area->max_lsp_lifetime[level - 1];
1110
1111 return rem_lifetime;
1112}
1113
1114static u_int16_t
1115lsp_refresh_time (struct isis_lsp *lsp, u_int16_t rem_lifetime)
1116{
1117 struct isis_area *area = lsp->area;
1118 int level = lsp->level;
1119 u_int16_t refresh_time;
1120
1121 /* Add jitter to LSP refresh time */
1122 refresh_time = isis_jitter (area->lsp_refresh[level - 1],
1123 MAX_LSP_GEN_JITTER);
1124
1125 /* RFC 4444 : make sure the refresh time is at least less than 300
1126 * of the remaining lifetime and more than gen interval */
1127 if (refresh_time <= area->lsp_gen_interval[level - 1] ||
1128 refresh_time > (rem_lifetime - 300))
1129 refresh_time = rem_lifetime - 300;
1130
Christian Franke9dfcca62015-11-10 18:32:11 +01001131 /* In cornercases, refresh_time might be <= lsp_gen_interval, however
1132 * we accept this violation to satisfy refresh_time <= rem_lifetime - 300 */
Josh Bailey3f045a02012-03-24 08:35:20 -07001133
1134 return refresh_time;
1135}
1136
hasso92365882005-01-18 13:53:33 +00001137static struct isis_lsp *
hassof390d2c2004-09-10 20:48:21 +00001138lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0, struct isis_area *area,
1139 int level)
jardineb5d44e2003-12-23 08:09:43 +00001140{
1141 struct isis_lsp *lsp;
hassof390d2c2004-09-10 20:48:21 +00001142 u_char frag_id[ISIS_SYS_ID_LEN + 2];
1143
jardineb5d44e2003-12-23 08:09:43 +00001144 memcpy (frag_id, lsp0->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 1);
1145 LSP_FRAGMENT (frag_id) = frag_num;
Josh Bailey3f045a02012-03-24 08:35:20 -07001146 /* FIXME add authentication TLV for fragment LSPs */
jardineb5d44e2003-12-23 08:09:43 +00001147 lsp = lsp_search (frag_id, area->lspdb[level - 1]);
hassof390d2c2004-09-10 20:48:21 +00001148 if (lsp)
1149 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001150 /* Clear the TLVs */
hassof390d2c2004-09-10 20:48:21 +00001151 lsp_clear_data (lsp);
hassof390d2c2004-09-10 20:48:21 +00001152 return lsp;
jardineb5d44e2003-12-23 08:09:43 +00001153 }
Christian Frankef1fc1db2015-11-10 18:43:31 +01001154 lsp = lsp_new (area, frag_id, ntohs(lsp0->lsp_header->rem_lifetime), 0,
Amritha Nambiarc8ee9402015-08-24 16:40:14 -07001155 lsp_bits_generate (level, area->overload_bit,
1156 area->attached_bit), 0, level);
Josh Bailey3f045a02012-03-24 08:35:20 -07001157 lsp->area = area;
jardineb5d44e2003-12-23 08:09:43 +00001158 lsp->own_lsp = 1;
hassof390d2c2004-09-10 20:48:21 +00001159 lsp_insert (lsp, area->lspdb[level - 1]);
jardineb5d44e2003-12-23 08:09:43 +00001160 listnode_add (lsp0->lspu.frags, lsp);
1161 lsp->lspu.zero_lsp = lsp0;
jardineb5d44e2003-12-23 08:09:43 +00001162 return lsp;
1163}
1164
Christian Frankeacf98652015-11-12 14:24:22 +01001165static void
1166lsp_build_ext_reach_ipv4(struct isis_lsp *lsp, struct isis_area *area,
1167 struct tlvs *tlv_data)
1168{
1169 struct route_table *er_table;
1170 struct route_node *rn;
1171 struct prefix_ipv4 *ipv4;
1172 struct isis_ext_info *info;
1173 struct ipv4_reachability *ipreach;
1174 struct te_ipv4_reachability *te_ipreach;
1175
1176 er_table = get_ext_reach(area, AF_INET, lsp->level);
1177 if (!er_table)
1178 return;
1179
1180 for (rn = route_top(er_table); rn; rn = route_next(rn))
1181 {
1182 if (!rn->info)
1183 continue;
1184
1185 ipv4 = (struct prefix_ipv4*)&rn->p;
1186 info = rn->info;
1187 if (area->oldmetric)
1188 {
1189 if (tlv_data->ipv4_ext_reachs == NULL)
1190 {
1191 tlv_data->ipv4_ext_reachs = list_new();
1192 tlv_data->ipv4_ext_reachs->del = free_tlv;
1193 }
1194 ipreach = XMALLOC(MTYPE_ISIS_TLV, sizeof(*ipreach));
1195
1196 ipreach->prefix.s_addr = ipv4->prefix.s_addr;
1197 masklen2ip(ipv4->prefixlen, &ipreach->mask);
1198 ipreach->prefix.s_addr &= ipreach->mask.s_addr;
1199
1200 if ((info->metric & 0x3f) != info->metric)
1201 ipreach->metrics.metric_default = 0x3f;
1202 else
1203 ipreach->metrics.metric_default = info->metric;
1204 ipreach->metrics.metric_expense = METRICS_UNSUPPORTED;
1205 ipreach->metrics.metric_error = METRICS_UNSUPPORTED;
1206 ipreach->metrics.metric_delay = METRICS_UNSUPPORTED;
1207 listnode_add(tlv_data->ipv4_ext_reachs, ipreach);
1208 }
1209 if (area->newmetric)
1210 {
1211 if (tlv_data->te_ipv4_reachs == NULL)
1212 {
1213 tlv_data->te_ipv4_reachs = list_new();
1214 tlv_data->te_ipv4_reachs->del = free_tlv;
1215 }
1216 te_ipreach =
1217 XCALLOC(MTYPE_ISIS_TLV,
1218 sizeof(*te_ipreach) - 1 + PSIZE(ipv4->prefixlen));
1219 if (info->metric > MAX_WIDE_PATH_METRIC)
1220 te_ipreach->te_metric = htonl(MAX_WIDE_PATH_METRIC);
1221 else
1222 te_ipreach->te_metric = htonl(info->metric);
1223 te_ipreach->control = ipv4->prefixlen & 0x3f;
1224 memcpy(&te_ipreach->prefix_start, &ipv4->prefix.s_addr,
1225 PSIZE(ipv4->prefixlen));
1226 listnode_add(tlv_data->te_ipv4_reachs, te_ipreach);
1227 }
1228 }
1229}
1230
1231static void
1232lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, struct isis_area *area,
1233 struct tlvs *tlv_data)
1234{
1235 struct route_table *er_table;
1236 struct route_node *rn;
1237 struct prefix_ipv6 *ipv6;
1238 struct isis_ext_info *info;
1239 struct ipv6_reachability *ip6reach;
1240
1241 er_table = get_ext_reach(area, AF_INET6, lsp->level);
1242 if (!er_table)
1243 return;
1244
1245 for (rn = route_top(er_table); rn; rn = route_next(rn))
1246 {
1247 if (!rn->info)
1248 continue;
1249
1250 ipv6 = (struct prefix_ipv6*)&rn->p;
1251 info = rn->info;
1252
1253 if (tlv_data->ipv6_reachs == NULL)
1254 {
1255 tlv_data->ipv6_reachs = list_new();
1256 tlv_data->ipv6_reachs->del = free_tlv;
1257 }
1258 ip6reach = XCALLOC(MTYPE_ISIS_TLV, sizeof(*ip6reach));
1259 if (info->metric > MAX_WIDE_PATH_METRIC)
1260 ip6reach->metric = htonl(MAX_WIDE_PATH_METRIC);
1261 else
1262 ip6reach->metric = htonl(info->metric);
1263 ip6reach->control_info = DISTRIBUTION_EXTERNAL;
1264 ip6reach->prefix_len = ipv6->prefixlen;
1265 memcpy(ip6reach->prefix, ipv6->prefix.s6_addr, sizeof(ip6reach->prefix));
1266 listnode_add(tlv_data->ipv6_reachs, ip6reach);
1267 }
1268}
1269
1270static void
1271lsp_build_ext_reach (struct isis_lsp *lsp, struct isis_area *area,
1272 struct tlvs *tlv_data)
1273{
1274 lsp_build_ext_reach_ipv4(lsp, area, tlv_data);
1275 lsp_build_ext_reach_ipv6(lsp, area, tlv_data);
1276}
1277
jardineb5d44e2003-12-23 08:09:43 +00001278/*
1279 * Builds the LSP data part. This func creates a new frag whenever
1280 * area->lsp_frag_threshold is exceeded.
1281 */
hasso92365882005-01-18 13:53:33 +00001282static void
Josh Bailey3f045a02012-03-24 08:35:20 -07001283lsp_build (struct isis_lsp *lsp, struct isis_area *area)
jardineb5d44e2003-12-23 08:09:43 +00001284{
1285 struct is_neigh *is_neigh;
hassoaa4376e2005-09-26 17:39:48 +00001286 struct te_is_neigh *te_is_neigh;
hasso3fdb2dd2005-09-28 18:45:54 +00001287 struct listnode *node, *ipnode;
jardineb5d44e2003-12-23 08:09:43 +00001288 int level = lsp->level;
1289 struct isis_circuit *circuit;
1290 struct prefix_ipv4 *ipv4;
1291 struct ipv4_reachability *ipreach;
hassoaa4376e2005-09-26 17:39:48 +00001292 struct te_ipv4_reachability *te_ipreach;
jardineb5d44e2003-12-23 08:09:43 +00001293 struct isis_adjacency *nei;
1294#ifdef HAVE_IPV6
Christian Frankee28718a2015-11-10 18:33:14 +01001295 struct prefix_ipv6 *ipv6, ip6prefix;
jardineb5d44e2003-12-23 08:09:43 +00001296 struct ipv6_reachability *ip6reach;
1297#endif /* HAVE_IPV6 */
1298 struct tlvs tlv_data;
1299 struct isis_lsp *lsp0 = lsp;
hasso18a6dce2004-10-03 18:18:34 +00001300 struct in_addr *routerid;
Josh Bailey3f045a02012-03-24 08:35:20 -07001301 uint32_t expected = 0, found = 0;
1302 uint32_t metric;
1303 u_char zero_id[ISIS_SYS_ID_LEN + 1];
1304 int retval = ISIS_OK;
Christian Franke80a8f722015-11-12 14:21:47 +01001305 char buf[BUFSIZ];
1306
1307 lsp_debug("ISIS (%s): Constructing local system LSP for level %d", area->area_tag, level);
Josh Bailey3f045a02012-03-24 08:35:20 -07001308
1309 /*
1310 * Building the zero lsp
1311 */
1312 memset (zero_id, 0, ISIS_SYS_ID_LEN + 1);
1313
1314 /* Reset stream endp. Stream is always there and on every LSP refresh only
1315 * TLV part of it is overwritten. So we must seek past header we will not
1316 * touch. */
1317 stream_reset (lsp->pdu);
1318 stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
1319
1320 /*
1321 * Add the authentication info if its present
1322 */
1323 lsp_auth_add (lsp);
jardineb5d44e2003-12-23 08:09:43 +00001324
1325 /*
1326 * First add the tlvs related to area
1327 */
hassof390d2c2004-09-10 20:48:21 +00001328
jardineb5d44e2003-12-23 08:09:43 +00001329 /* Area addresses */
1330 if (lsp->tlv_data.area_addrs == NULL)
1331 lsp->tlv_data.area_addrs = list_new ();
1332 list_add_list (lsp->tlv_data.area_addrs, area->area_addrs);
Josh Bailey3f045a02012-03-24 08:35:20 -07001333 if (listcount (lsp->tlv_data.area_addrs) > 0)
1334 tlv_add_area_addrs (lsp->tlv_data.area_addrs, lsp->pdu);
1335
jardineb5d44e2003-12-23 08:09:43 +00001336 /* Protocols Supported */
hassof390d2c2004-09-10 20:48:21 +00001337 if (area->ip_circuits > 0
jardineb5d44e2003-12-23 08:09:43 +00001338#ifdef HAVE_IPV6
1339 || area->ipv6_circuits > 0
1340#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +00001341 )
jardineb5d44e2003-12-23 08:09:43 +00001342 {
hassoaac372f2005-09-01 17:52:33 +00001343 lsp->tlv_data.nlpids = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct nlpids));
jardineb5d44e2003-12-23 08:09:43 +00001344 lsp->tlv_data.nlpids->count = 0;
hassof390d2c2004-09-10 20:48:21 +00001345 if (area->ip_circuits > 0)
1346 {
Christian Franke80a8f722015-11-12 14:21:47 +01001347 lsp_debug("ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs", area->area_tag);
hassof390d2c2004-09-10 20:48:21 +00001348 lsp->tlv_data.nlpids->count++;
1349 lsp->tlv_data.nlpids->nlpids[0] = NLPID_IP;
1350 }
jardineb5d44e2003-12-23 08:09:43 +00001351#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +00001352 if (area->ipv6_circuits > 0)
1353 {
Christian Franke80a8f722015-11-12 14:21:47 +01001354 lsp_debug("ISIS (%s): Found IPv6 circuit, adding IPv6 to NLPIDs", area->area_tag);
hassof390d2c2004-09-10 20:48:21 +00001355 lsp->tlv_data.nlpids->count++;
1356 lsp->tlv_data.nlpids->nlpids[lsp->tlv_data.nlpids->count - 1] =
1357 NLPID_IPV6;
1358 }
jardineb5d44e2003-12-23 08:09:43 +00001359#endif /* HAVE_IPV6 */
Josh Bailey3f045a02012-03-24 08:35:20 -07001360 tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu);
jardineb5d44e2003-12-23 08:09:43 +00001361 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001362
jardineb5d44e2003-12-23 08:09:43 +00001363 /* Dynamic Hostname */
hassof390d2c2004-09-10 20:48:21 +00001364 if (area->dynhostname)
1365 {
Christian Frankef35169e2015-11-12 14:09:08 +01001366 const char *hostname = unix_hostname();
1367 size_t hostname_len = strlen(hostname);
1368
hassof390d2c2004-09-10 20:48:21 +00001369 lsp->tlv_data.hostname = XMALLOC (MTYPE_ISIS_TLV,
1370 sizeof (struct hostname));
jardin9e867fe2003-12-23 08:56:18 +00001371
Christian Frankef35169e2015-11-12 14:09:08 +01001372 strncpy((char *)lsp->tlv_data.hostname->name, hostname,
1373 sizeof(lsp->tlv_data.hostname->name));
1374 if (hostname_len <= MAX_TLV_LEN)
1375 lsp->tlv_data.hostname->namelen = hostname_len;
1376 else
1377 lsp->tlv_data.hostname->namelen = MAX_TLV_LEN;
1378
Christian Franke80a8f722015-11-12 14:21:47 +01001379 lsp_debug("ISIS (%s): Adding dynamic hostname '%.*s'", area->area_tag,
1380 lsp->tlv_data.hostname->namelen, lsp->tlv_data.hostname->name);
Josh Bailey3f045a02012-03-24 08:35:20 -07001381 tlv_add_dynamic_hostname (lsp->tlv_data.hostname, lsp->pdu);
hassof390d2c2004-09-10 20:48:21 +00001382 }
Christian Franke80a8f722015-11-12 14:21:47 +01001383 else
1384 {
1385 lsp_debug("ISIS (%s): Not adding dynamic hostname (disabled)", area->area_tag);
1386 }
jardineb5d44e2003-12-23 08:09:43 +00001387
hasso81ad8f62005-09-26 17:58:24 +00001388 /* IPv4 address and TE router ID TLVs. In case of the first one we don't
1389 * follow "C" vendor, but "J" vendor behavior - one IPv4 address is put into
1390 * LSP and this address is same as router id. */
Josh Bailey3f045a02012-03-24 08:35:20 -07001391 if (isis->router_id != 0)
hasso18a6dce2004-10-03 18:18:34 +00001392 {
Christian Franke80a8f722015-11-12 14:21:47 +01001393 inet_ntop(AF_INET, &isis->router_id, buf, sizeof(buf));
1394 lsp_debug("ISIS (%s): Adding router ID %s as IPv4 tlv.", area->area_tag, buf);
hasso18a6dce2004-10-03 18:18:34 +00001395 if (lsp->tlv_data.ipv4_addrs == NULL)
hassobe7d65d2005-09-02 01:38:16 +00001396 {
1397 lsp->tlv_data.ipv4_addrs = list_new ();
1398 lsp->tlv_data.ipv4_addrs->del = free_tlv;
1399 }
hasso18a6dce2004-10-03 18:18:34 +00001400
1401 routerid = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct in_addr));
Josh Bailey3f045a02012-03-24 08:35:20 -07001402 routerid->s_addr = isis->router_id;
hasso18a6dce2004-10-03 18:18:34 +00001403 listnode_add (lsp->tlv_data.ipv4_addrs, routerid);
hasso81ad8f62005-09-26 17:58:24 +00001404 tlv_add_in_addr (routerid, lsp->pdu, IPV4_ADDR);
hasso18a6dce2004-10-03 18:18:34 +00001405
hasso81ad8f62005-09-26 17:58:24 +00001406 /* Exactly same data is put into TE router ID TLV, but only if new style
1407 * TLV's are in use. */
1408 if (area->newmetric)
1409 {
Christian Franke80a8f722015-11-12 14:21:47 +01001410 lsp_debug("ISIS (%s): Adding router ID also as TE router ID tlv.", area->area_tag);
hasso81ad8f62005-09-26 17:58:24 +00001411 lsp->tlv_data.router_id = XMALLOC (MTYPE_ISIS_TLV,
1412 sizeof (struct in_addr));
Josh Bailey3f045a02012-03-24 08:35:20 -07001413 lsp->tlv_data.router_id->id.s_addr = isis->router_id;
1414 tlv_add_in_addr (&lsp->tlv_data.router_id->id, lsp->pdu,
1415 TE_ROUTER_ID);
hasso81ad8f62005-09-26 17:58:24 +00001416 }
hasso18a6dce2004-10-03 18:18:34 +00001417 }
Christian Franke80a8f722015-11-12 14:21:47 +01001418 else
1419 {
1420 lsp_debug("ISIS (%s): Router ID is unset. Not adding tlv.", area->area_tag);
1421 }
hassof1082d12005-09-19 04:23:34 +00001422
hasso81ad8f62005-09-26 17:58:24 +00001423 memset (&tlv_data, 0, sizeof (struct tlvs));
1424
hassof1082d12005-09-19 04:23:34 +00001425#ifdef TOPOLOGY_GENERATE
1426 /* If topology exists (and we create topology for level 1 only), create
1427 * (hardcoded) link to topology. */
Josh Bailey3f045a02012-03-24 08:35:20 -07001428 if (area->topology && level == IS_LEVEL_1)
hassof1082d12005-09-19 04:23:34 +00001429 {
1430 if (tlv_data.is_neighs == NULL)
hassoaa4376e2005-09-26 17:39:48 +00001431 {
1432 tlv_data.is_neighs = list_new ();
1433 tlv_data.is_neighs->del = free_tlv;
1434 }
hasso3fdb2dd2005-09-28 18:45:54 +00001435 is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
hassof1082d12005-09-19 04:23:34 +00001436
1437 memcpy (&is_neigh->neigh_id, area->topology_baseis, ISIS_SYS_ID_LEN);
1438 is_neigh->neigh_id[ISIS_SYS_ID_LEN - 1] = (1 & 0xFF);
1439 is_neigh->neigh_id[ISIS_SYS_ID_LEN - 2] = ((1 >> 8) & 0xFF);
1440 is_neigh->metrics.metric_default = 0x01;
1441 is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED;
1442 is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED;
1443 is_neigh->metrics.metric_error = METRICS_UNSUPPORTED;
1444 listnode_add (tlv_data.is_neighs, is_neigh);
1445 }
1446#endif /* TOPOLOGY_GENERATE */
1447
Christian Franke80a8f722015-11-12 14:21:47 +01001448 lsp_debug("ISIS (%s): Adding circuit specific information.", area->area_tag);
1449
hasso18a6dce2004-10-03 18:18:34 +00001450 /*
jardineb5d44e2003-12-23 08:09:43 +00001451 * Then build lists of tlvs related to circuits
1452 */
hasso3fdb2dd2005-09-28 18:45:54 +00001453 for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit))
hassof390d2c2004-09-10 20:48:21 +00001454 {
Christian Franke80a8f722015-11-12 14:21:47 +01001455 if (!circuit->interface)
1456 lsp_debug("ISIS (%s): Processing %s circuit %p with unknown interface",
1457 area->area_tag, circuit_type2string(circuit->circ_type), circuit);
1458 else
1459 lsp_debug("ISIS (%s): Processing %s circuit %s",
1460 area->area_tag, circuit_type2string(circuit->circ_type), circuit->interface->name);
1461
hassof390d2c2004-09-10 20:48:21 +00001462 if (circuit->state != C_STATE_UP)
Christian Franke80a8f722015-11-12 14:21:47 +01001463 {
1464 lsp_debug("ISIS (%s): Circuit is not up, ignoring.", area->area_tag);
1465 continue;
1466 }
jardineb5d44e2003-12-23 08:09:43 +00001467
hassof390d2c2004-09-10 20:48:21 +00001468 /*
1469 * Add IPv4 internal reachability of this circuit
1470 */
1471 if (circuit->ip_router && circuit->ip_addrs &&
1472 circuit->ip_addrs->count > 0)
1473 {
Christian Franke80a8f722015-11-12 14:21:47 +01001474 lsp_debug("ISIS (%s): Circuit has IPv4 active, adding respective TLVs.", area->area_tag);
hassoaa4376e2005-09-26 17:39:48 +00001475 if (area->oldmetric)
hassof390d2c2004-09-10 20:48:21 +00001476 {
hassoaa4376e2005-09-26 17:39:48 +00001477 if (tlv_data.ipv4_int_reachs == NULL)
1478 {
1479 tlv_data.ipv4_int_reachs = list_new ();
1480 tlv_data.ipv4_int_reachs->del = free_tlv;
1481 }
hasso3fdb2dd2005-09-28 18:45:54 +00001482 for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, ipnode, ipv4))
hassoaa4376e2005-09-26 17:39:48 +00001483 {
1484 ipreach =
1485 XMALLOC (MTYPE_ISIS_TLV, sizeof (struct ipv4_reachability));
1486 ipreach->metrics = circuit->metrics[level - 1];
1487 masklen2ip (ipv4->prefixlen, &ipreach->mask);
1488 ipreach->prefix.s_addr = ((ipreach->mask.s_addr) &
1489 (ipv4->prefix.s_addr));
Christian Franke80a8f722015-11-12 14:21:47 +01001490 inet_ntop(AF_INET, &ipreach->prefix.s_addr, buf, sizeof(buf));
1491 lsp_debug("ISIS (%s): Adding old-style IP reachability for %s/%d",
1492 area->area_tag, buf, ipv4->prefixlen);
hassoaa4376e2005-09-26 17:39:48 +00001493 listnode_add (tlv_data.ipv4_int_reachs, ipreach);
1494 }
hassof390d2c2004-09-10 20:48:21 +00001495 }
hassoaa4376e2005-09-26 17:39:48 +00001496 if (area->newmetric)
hassof390d2c2004-09-10 20:48:21 +00001497 {
hassoaa4376e2005-09-26 17:39:48 +00001498 if (tlv_data.te_ipv4_reachs == NULL)
1499 {
1500 tlv_data.te_ipv4_reachs = list_new ();
1501 tlv_data.te_ipv4_reachs->del = free_tlv;
1502 }
hasso3fdb2dd2005-09-28 18:45:54 +00001503 for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, ipnode, ipv4))
hassoaa4376e2005-09-26 17:39:48 +00001504 {
1505 /* FIXME All this assumes that we have no sub TLVs. */
1506 te_ipreach = XCALLOC (MTYPE_ISIS_TLV,
1507 sizeof (struct te_ipv4_reachability) +
1508 ((ipv4->prefixlen + 7)/8) - 1);
hasso309ddb12005-09-26 18:06:47 +00001509
1510 if (area->oldmetric)
1511 te_ipreach->te_metric = htonl (circuit->metrics[level - 1].metric_default);
1512 else
1513 te_ipreach->te_metric = htonl (circuit->te_metric[level - 1]);
1514
hassoaa4376e2005-09-26 17:39:48 +00001515 te_ipreach->control = (ipv4->prefixlen & 0x3F);
1516 memcpy (&te_ipreach->prefix_start, &ipv4->prefix.s_addr,
1517 (ipv4->prefixlen + 7)/8);
Christian Franke80a8f722015-11-12 14:21:47 +01001518 inet_ntop(AF_INET, &ipv4->prefix.s_addr, buf, sizeof(buf));
1519 lsp_debug("ISIS (%s): Adding te-style IP reachability for %s/%d",
1520 area->area_tag, buf, ipv4->prefixlen);
hassoaa4376e2005-09-26 17:39:48 +00001521 listnode_add (tlv_data.te_ipv4_reachs, te_ipreach);
1522 }
hassof390d2c2004-09-10 20:48:21 +00001523 }
hassof390d2c2004-09-10 20:48:21 +00001524 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001525
jardineb5d44e2003-12-23 08:09:43 +00001526#ifdef HAVE_IPV6
hassof390d2c2004-09-10 20:48:21 +00001527 /*
1528 * Add IPv6 reachability of this circuit
1529 */
1530 if (circuit->ipv6_router && circuit->ipv6_non_link &&
1531 circuit->ipv6_non_link->count > 0)
1532 {
1533
1534 if (tlv_data.ipv6_reachs == NULL)
1535 {
1536 tlv_data.ipv6_reachs = list_new ();
hassobe7d65d2005-09-02 01:38:16 +00001537 tlv_data.ipv6_reachs->del = free_tlv;
hassof390d2c2004-09-10 20:48:21 +00001538 }
hasso3fdb2dd2005-09-28 18:45:54 +00001539 for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, ipnode, ipv6))
hassof390d2c2004-09-10 20:48:21 +00001540 {
hassof390d2c2004-09-10 20:48:21 +00001541 ip6reach =
hassoaac372f2005-09-01 17:52:33 +00001542 XCALLOC (MTYPE_ISIS_TLV, sizeof (struct ipv6_reachability));
hasso309ddb12005-09-26 18:06:47 +00001543
1544 if (area->oldmetric)
1545 ip6reach->metric =
1546 htonl (circuit->metrics[level - 1].metric_default);
1547 else
1548 ip6reach->metric = htonl (circuit->te_metric[level - 1]);
1549
hassof390d2c2004-09-10 20:48:21 +00001550 ip6reach->control_info = 0;
1551 ip6reach->prefix_len = ipv6->prefixlen;
Christian Frankee28718a2015-11-10 18:33:14 +01001552 memcpy(&ip6prefix, ipv6, sizeof(ip6prefix));
1553 apply_mask_ipv6(&ip6prefix);
Christian Franke80a8f722015-11-12 14:21:47 +01001554
Christian Frankee28718a2015-11-10 18:33:14 +01001555 inet_ntop(AF_INET6, &ip6prefix.prefix.s6_addr, buf, sizeof(buf));
Christian Franke80a8f722015-11-12 14:21:47 +01001556 lsp_debug("ISIS (%s): Adding IPv6 reachability for %s/%d",
1557 area->area_tag, buf, ipv6->prefixlen);
1558
Christian Frankee28718a2015-11-10 18:33:14 +01001559 memcpy (ip6reach->prefix, ip6prefix.prefix.s6_addr,
hasso67851572004-09-21 14:17:04 +00001560 sizeof (ip6reach->prefix));
hassof390d2c2004-09-10 20:48:21 +00001561 listnode_add (tlv_data.ipv6_reachs, ip6reach);
1562 }
1563 }
1564#endif /* HAVE_IPV6 */
1565
1566 switch (circuit->circ_type)
1567 {
1568 case CIRCUIT_T_BROADCAST:
Josh Bailey3f045a02012-03-24 08:35:20 -07001569 if (level & circuit->is_type)
hassof390d2c2004-09-10 20:48:21 +00001570 {
hassoaa4376e2005-09-26 17:39:48 +00001571 if (area->oldmetric)
hassof390d2c2004-09-10 20:48:21 +00001572 {
hassoaa4376e2005-09-26 17:39:48 +00001573 if (tlv_data.is_neighs == NULL)
1574 {
1575 tlv_data.is_neighs = list_new ();
1576 tlv_data.is_neighs->del = free_tlv;
1577 }
1578 is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
Josh Bailey3f045a02012-03-24 08:35:20 -07001579 if (level == IS_LEVEL_1)
hassoaa4376e2005-09-26 17:39:48 +00001580 memcpy (is_neigh->neigh_id,
1581 circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
1582 else
1583 memcpy (is_neigh->neigh_id,
1584 circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
1585 is_neigh->metrics = circuit->metrics[level - 1];
Josh Bailey3f045a02012-03-24 08:35:20 -07001586 if (!memcmp (is_neigh->neigh_id, zero_id,
1587 ISIS_SYS_ID_LEN + 1))
Christian Franke80a8f722015-11-12 14:21:47 +01001588 {
1589 XFREE (MTYPE_ISIS_TLV, is_neigh);
1590 lsp_debug("ISIS (%s): No DIS for circuit, not adding old-style IS neighbor.",
1591 area->area_tag);
1592 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001593 else
Christian Franke80a8f722015-11-12 14:21:47 +01001594 {
1595 listnode_add (tlv_data.is_neighs, is_neigh);
1596 lsp_debug("ISIS (%s): Adding DIS %s.%02x as old-style neighbor",
1597 area->area_tag, sysid_print(is_neigh->neigh_id),
1598 LSP_PSEUDO_ID(is_neigh->neigh_id));
1599 }
hassof390d2c2004-09-10 20:48:21 +00001600 }
hassoaa4376e2005-09-26 17:39:48 +00001601 if (area->newmetric)
1602 {
hassoaa4376e2005-09-26 17:39:48 +00001603 if (tlv_data.te_is_neighs == NULL)
1604 {
1605 tlv_data.te_is_neighs = list_new ();
1606 tlv_data.te_is_neighs->del = free_tlv;
1607 }
1608 te_is_neigh = XCALLOC (MTYPE_ISIS_TLV,
1609 sizeof (struct te_is_neigh));
Josh Bailey3f045a02012-03-24 08:35:20 -07001610 if (level == IS_LEVEL_1)
hassoaa4376e2005-09-26 17:39:48 +00001611 memcpy (te_is_neigh->neigh_id,
1612 circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
1613 else
1614 memcpy (te_is_neigh->neigh_id,
1615 circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
hasso309ddb12005-09-26 18:06:47 +00001616 if (area->oldmetric)
Josh Bailey3f045a02012-03-24 08:35:20 -07001617 metric = circuit->metrics[level - 1].metric_default;
hasso309ddb12005-09-26 18:06:47 +00001618 else
Josh Bailey3f045a02012-03-24 08:35:20 -07001619 metric = circuit->te_metric[level - 1];
1620 SET_TE_METRIC(te_is_neigh, metric);
1621 if (!memcmp (te_is_neigh->neigh_id, zero_id,
1622 ISIS_SYS_ID_LEN + 1))
Christian Franke80a8f722015-11-12 14:21:47 +01001623 {
1624 XFREE (MTYPE_ISIS_TLV, te_is_neigh);
1625 lsp_debug("ISIS (%s): No DIS for circuit, not adding te-style IS neighbor.",
1626 area->area_tag);
1627 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001628 else
Christian Franke80a8f722015-11-12 14:21:47 +01001629 {
1630 listnode_add (tlv_data.te_is_neighs, te_is_neigh);
1631 lsp_debug("ISIS (%s): Adding DIS %s.%02x as te-style neighbor",
1632 area->area_tag, sysid_print(te_is_neigh->neigh_id),
1633 LSP_PSEUDO_ID(te_is_neigh->neigh_id));
1634 }
hassoaa4376e2005-09-26 17:39:48 +00001635 }
hassof390d2c2004-09-10 20:48:21 +00001636 }
Christian Franke80a8f722015-11-12 14:21:47 +01001637 else
1638 {
1639 lsp_debug("ISIS (%s): Circuit is not active for current level. Not adding IS neighbors",
1640 area->area_tag);
1641 }
hassof390d2c2004-09-10 20:48:21 +00001642 break;
1643 case CIRCUIT_T_P2P:
1644 nei = circuit->u.p2p.neighbor;
1645 if (nei && (level & nei->circuit_t))
1646 {
hassoaa4376e2005-09-26 17:39:48 +00001647 if (area->oldmetric)
hassof390d2c2004-09-10 20:48:21 +00001648 {
hassoaa4376e2005-09-26 17:39:48 +00001649 if (tlv_data.is_neighs == NULL)
1650 {
1651 tlv_data.is_neighs = list_new ();
1652 tlv_data.is_neighs->del = free_tlv;
1653 }
1654 is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
1655 memcpy (is_neigh->neigh_id, nei->sysid, ISIS_SYS_ID_LEN);
1656 is_neigh->metrics = circuit->metrics[level - 1];
1657 listnode_add (tlv_data.is_neighs, is_neigh);
Christian Franke80a8f722015-11-12 14:21:47 +01001658 lsp_debug("ISIS (%s): Adding old-style is reach for %s", area->area_tag,
1659 sysid_print(is_neigh->neigh_id));
hassof390d2c2004-09-10 20:48:21 +00001660 }
hassoaa4376e2005-09-26 17:39:48 +00001661 if (area->newmetric)
1662 {
1663 uint32_t metric;
1664
1665 if (tlv_data.te_is_neighs == NULL)
1666 {
1667 tlv_data.te_is_neighs = list_new ();
1668 tlv_data.te_is_neighs->del = free_tlv;
1669 }
1670 te_is_neigh = XCALLOC (MTYPE_ISIS_TLV,
1671 sizeof (struct te_is_neigh));
1672 memcpy (te_is_neigh->neigh_id, nei->sysid, ISIS_SYS_ID_LEN);
Josh Bailey3f045a02012-03-24 08:35:20 -07001673 metric = circuit->te_metric[level - 1];
1674 SET_TE_METRIC(te_is_neigh, metric);
hassoaa4376e2005-09-26 17:39:48 +00001675 listnode_add (tlv_data.te_is_neighs, te_is_neigh);
Christian Franke80a8f722015-11-12 14:21:47 +01001676 lsp_debug("ISIS (%s): Adding te-style is reach for %s", area->area_tag,
1677 sysid_print(te_is_neigh->neigh_id));
hassoaa4376e2005-09-26 17:39:48 +00001678 }
hassof390d2c2004-09-10 20:48:21 +00001679 }
Christian Franke80a8f722015-11-12 14:21:47 +01001680 else
1681 {
1682 lsp_debug("ISIS (%s): No adjacency for given level on this circuit. Not adding IS neighbors",
1683 area->area_tag);
1684 }
hassof390d2c2004-09-10 20:48:21 +00001685 break;
Josh Bailey3f045a02012-03-24 08:35:20 -07001686 case CIRCUIT_T_LOOPBACK:
1687 break;
hassof390d2c2004-09-10 20:48:21 +00001688 default:
1689 zlog_warn ("lsp_area_create: unknown circuit type");
1690 }
1691 }
1692
Christian Frankeacf98652015-11-12 14:24:22 +01001693 lsp_build_ext_reach(lsp, area, &tlv_data);
1694
Christian Franke80a8f722015-11-12 14:21:47 +01001695 lsp_debug("ISIS (%s): LSP construction is complete. Serializing...", area->area_tag);
1696
hassof390d2c2004-09-10 20:48:21 +00001697 while (tlv_data.ipv4_int_reachs && listcount (tlv_data.ipv4_int_reachs))
1698 {
1699 if (lsp->tlv_data.ipv4_int_reachs == NULL)
1700 lsp->tlv_data.ipv4_int_reachs = list_new ();
1701 lsp_tlv_fit (lsp, &tlv_data.ipv4_int_reachs,
1702 &lsp->tlv_data.ipv4_int_reachs,
1703 IPV4_REACH_LEN, area->lsp_frag_threshold,
Christian Frankeacf98652015-11-12 14:24:22 +01001704 tlv_add_ipv4_int_reachs);
hassof390d2c2004-09-10 20:48:21 +00001705 if (tlv_data.ipv4_int_reachs && listcount (tlv_data.ipv4_int_reachs))
1706 lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
1707 lsp0, area, level);
1708 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001709
Christian Frankeacf98652015-11-12 14:24:22 +01001710 while (tlv_data.ipv4_ext_reachs && listcount (tlv_data.ipv4_ext_reachs))
1711 {
1712 if (lsp->tlv_data.ipv4_ext_reachs == NULL)
1713 lsp->tlv_data.ipv4_ext_reachs = list_new ();
1714 lsp_tlv_fit (lsp, &tlv_data.ipv4_ext_reachs,
1715 &lsp->tlv_data.ipv4_ext_reachs,
1716 IPV4_REACH_LEN, area->lsp_frag_threshold,
1717 tlv_add_ipv4_ext_reachs);
1718 if (tlv_data.ipv4_ext_reachs && listcount (tlv_data.ipv4_ext_reachs))
1719 lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
1720 lsp0, area, level);
1721 }
1722
hassoaa4376e2005-09-26 17:39:48 +00001723 /* FIXME: We pass maximum te_ipv4_reachability length to the lsp_tlv_fit()
1724 * for now. lsp_tlv_fit() needs to be fixed to deal with variable length
1725 * TLVs (sub TLVs!). */
1726 while (tlv_data.te_ipv4_reachs && listcount (tlv_data.te_ipv4_reachs))
1727 {
1728 if (lsp->tlv_data.te_ipv4_reachs == NULL)
1729 lsp->tlv_data.te_ipv4_reachs = list_new ();
1730 lsp_tlv_fit (lsp, &tlv_data.te_ipv4_reachs,
1731 &lsp->tlv_data.te_ipv4_reachs,
Josh Bailey3f045a02012-03-24 08:35:20 -07001732 TE_IPV4_REACH_LEN, area->lsp_frag_threshold,
1733 tlv_add_te_ipv4_reachs);
hassoaa4376e2005-09-26 17:39:48 +00001734 if (tlv_data.te_ipv4_reachs && listcount (tlv_data.te_ipv4_reachs))
1735 lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
1736 lsp0, area, level);
1737 }
hassof390d2c2004-09-10 20:48:21 +00001738
1739#ifdef HAVE_IPV6
1740 while (tlv_data.ipv6_reachs && listcount (tlv_data.ipv6_reachs))
1741 {
1742 if (lsp->tlv_data.ipv6_reachs == NULL)
1743 lsp->tlv_data.ipv6_reachs = list_new ();
1744 lsp_tlv_fit (lsp, &tlv_data.ipv6_reachs,
1745 &lsp->tlv_data.ipv6_reachs,
1746 IPV6_REACH_LEN, area->lsp_frag_threshold,
1747 tlv_add_ipv6_reachs);
1748 if (tlv_data.ipv6_reachs && listcount (tlv_data.ipv6_reachs))
1749 lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
1750 lsp0, area, level);
jardineb5d44e2003-12-23 08:09:43 +00001751 }
1752#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +00001753
1754 while (tlv_data.is_neighs && listcount (tlv_data.is_neighs))
1755 {
1756 if (lsp->tlv_data.is_neighs == NULL)
1757 lsp->tlv_data.is_neighs = list_new ();
1758 lsp_tlv_fit (lsp, &tlv_data.is_neighs,
1759 &lsp->tlv_data.is_neighs,
1760 IS_NEIGHBOURS_LEN, area->lsp_frag_threshold,
1761 tlv_add_is_neighs);
1762 if (tlv_data.is_neighs && listcount (tlv_data.is_neighs))
1763 lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
1764 lsp0, area, level);
jardineb5d44e2003-12-23 08:09:43 +00001765 }
jardineb5d44e2003-12-23 08:09:43 +00001766
hassoaa4376e2005-09-26 17:39:48 +00001767 while (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs))
1768 {
1769 if (lsp->tlv_data.te_is_neighs == NULL)
1770 lsp->tlv_data.te_is_neighs = list_new ();
1771 lsp_tlv_fit (lsp, &tlv_data.te_is_neighs, &lsp->tlv_data.te_is_neighs,
1772 IS_NEIGHBOURS_LEN, area->lsp_frag_threshold,
1773 tlv_add_te_is_neighs);
1774 if (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs))
1775 lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
1776 lsp0, area, level);
1777 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001778 lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
hassoaa4376e2005-09-26 17:39:48 +00001779
1780 free_tlvs (&tlv_data);
Josh Bailey3f045a02012-03-24 08:35:20 -07001781
1782 /* Validate the LSP */
1783 retval = parse_tlvs (area->area_tag, STREAM_DATA (lsp->pdu) +
1784 ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN,
1785 stream_get_endp (lsp->pdu) -
1786 ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN,
1787 &expected, &found, &tlv_data, NULL);
1788 assert (retval == ISIS_OK);
1789
jardineb5d44e2003-12-23 08:09:43 +00001790 return;
1791}
jardineb5d44e2003-12-23 08:09:43 +00001792
1793/*
Josh Bailey3f045a02012-03-24 08:35:20 -07001794 * 7.3.7 and 7.3.9 Generation on non-pseudonode LSPs
jardineb5d44e2003-12-23 08:09:43 +00001795 */
Josh Bailey3f045a02012-03-24 08:35:20 -07001796int
1797lsp_generate (struct isis_area *area, int level)
hassof390d2c2004-09-10 20:48:21 +00001798{
jardineb5d44e2003-12-23 08:09:43 +00001799 struct isis_lsp *oldlsp, *newlsp;
1800 u_int32_t seq_num = 0;
1801 u_char lspid[ISIS_SYS_ID_LEN + 2];
Josh Bailey3f045a02012-03-24 08:35:20 -07001802 u_int16_t rem_lifetime, refresh_time;
1803
1804 if ((area == NULL) || (area->is_type & level) != level)
1805 return ISIS_ERROR;
jardineb5d44e2003-12-23 08:09:43 +00001806
1807 memset (&lspid, 0, ISIS_SYS_ID_LEN + 2);
1808 memcpy (&lspid, isis->sysid, ISIS_SYS_ID_LEN);
1809
1810 /* only builds the lsp if the area shares the level */
Josh Bailey3f045a02012-03-24 08:35:20 -07001811 oldlsp = lsp_search (lspid, area->lspdb[level - 1]);
1812 if (oldlsp)
hassof390d2c2004-09-10 20:48:21 +00001813 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001814 /* FIXME: we should actually initiate a purge */
1815 seq_num = ntohl (oldlsp->lsp_header->seq_num);
1816 lsp_search_and_destroy (oldlsp->lsp_header->lsp_id,
1817 area->lspdb[level - 1]);
hassof390d2c2004-09-10 20:48:21 +00001818 }
Josh Bailey3f045a02012-03-24 08:35:20 -07001819 rem_lifetime = lsp_rem_lifetime (area, level);
Christian Frankef1fc1db2015-11-10 18:43:31 +01001820 newlsp = lsp_new (area, lspid, rem_lifetime, seq_num,
Amritha Nambiarc8ee9402015-08-24 16:40:14 -07001821 area->is_type | area->overload_bit | area->attached_bit,
1822 0, level);
Josh Bailey3f045a02012-03-24 08:35:20 -07001823 newlsp->area = area;
1824 newlsp->own_lsp = 1;
jardineb5d44e2003-12-23 08:09:43 +00001825
Josh Bailey3f045a02012-03-24 08:35:20 -07001826 lsp_insert (newlsp, area->lspdb[level - 1]);
1827 /* build_lsp_data (newlsp, area); */
1828 lsp_build (newlsp, area);
1829 /* time to calculate our checksum */
1830 lsp_seqnum_update (newlsp);
Christian Franke61010c32015-11-10 18:43:34 +01001831 newlsp->last_generated = time(NULL);
Josh Bailey3f045a02012-03-24 08:35:20 -07001832 lsp_set_all_srmflags (newlsp);
1833
1834 refresh_time = lsp_refresh_time (newlsp, rem_lifetime);
Christian Franke61010c32015-11-10 18:43:34 +01001835
Josh Bailey3f045a02012-03-24 08:35:20 -07001836 THREAD_TIMER_OFF (area->t_lsp_refresh[level - 1]);
Christian Franke61010c32015-11-10 18:43:34 +01001837 area->lsp_regenerate_pending[level - 1] = 0;
Josh Bailey3f045a02012-03-24 08:35:20 -07001838 if (level == IS_LEVEL_1)
1839 THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
1840 lsp_l1_refresh, area, refresh_time);
1841 else if (level == IS_LEVEL_2)
1842 THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
1843 lsp_l2_refresh, area, refresh_time);
1844
1845 if (isis->debugs & DEBUG_UPDATE_PACKETS)
hassof390d2c2004-09-10 20:48:21 +00001846 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001847 zlog_debug ("ISIS-Upd (%s): Building L%d LSP %s, len %d, "
1848 "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us",
1849 area->area_tag, level,
1850 rawlspid_print (newlsp->lsp_header->lsp_id),
1851 ntohl (newlsp->lsp_header->pdu_len),
1852 ntohl (newlsp->lsp_header->seq_num),
1853 ntohs (newlsp->lsp_header->checksum),
1854 ntohs (newlsp->lsp_header->rem_lifetime),
1855 refresh_time);
hassof390d2c2004-09-10 20:48:21 +00001856 }
Christian Franke61010c32015-11-10 18:43:34 +01001857 sched_debug("ISIS (%s): Built L%d LSP. Set triggered regenerate to non-pending.",
1858 area->area_tag, level);
jardineb5d44e2003-12-23 08:09:43 +00001859
1860 return ISIS_OK;
1861}
1862
1863/*
Josh Bailey3f045a02012-03-24 08:35:20 -07001864 * Search own LSPs, update holding time and set SRM
jardineb5d44e2003-12-23 08:09:43 +00001865 */
hasso92365882005-01-18 13:53:33 +00001866static int
Josh Bailey3f045a02012-03-24 08:35:20 -07001867lsp_regenerate (struct isis_area *area, int level)
jardineb5d44e2003-12-23 08:09:43 +00001868{
David Lampartere8aca322012-11-27 01:10:30 +00001869 dict_t *lspdb;
jardineb5d44e2003-12-23 08:09:43 +00001870 struct isis_lsp *lsp, *frag;
1871 struct listnode *node;
1872 u_char lspid[ISIS_SYS_ID_LEN + 2];
Josh Bailey3f045a02012-03-24 08:35:20 -07001873 u_int16_t rem_lifetime, refresh_time;
1874
1875 if ((area == NULL) || (area->is_type & level) != level)
1876 return ISIS_ERROR;
jardineb5d44e2003-12-23 08:09:43 +00001877
David Lampartere8aca322012-11-27 01:10:30 +00001878 lspdb = area->lspdb[level - 1];
1879
jardineb5d44e2003-12-23 08:09:43 +00001880 memset (lspid, 0, ISIS_SYS_ID_LEN + 2);
1881 memcpy (lspid, isis->sysid, ISIS_SYS_ID_LEN);
hassof390d2c2004-09-10 20:48:21 +00001882
jardineb5d44e2003-12-23 08:09:43 +00001883 lsp = lsp_search (lspid, lspdb);
jardineb5d44e2003-12-23 08:09:43 +00001884
hassof390d2c2004-09-10 20:48:21 +00001885 if (!lsp)
1886 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001887 zlog_err ("ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!",
1888 area->area_tag, level);
hassof390d2c2004-09-10 20:48:21 +00001889 return ISIS_ERROR;
1890 }
1891
1892 lsp_clear_data (lsp);
Josh Bailey3f045a02012-03-24 08:35:20 -07001893 lsp_build (lsp, area);
Amritha Nambiarc8ee9402015-08-24 16:40:14 -07001894 lsp->lsp_header->lsp_bits = lsp_bits_generate (level, area->overload_bit,
1895 area->attached_bit);
Josh Bailey3f045a02012-03-24 08:35:20 -07001896 rem_lifetime = lsp_rem_lifetime (area, level);
1897 lsp->lsp_header->rem_lifetime = htons (rem_lifetime);
jardineb5d44e2003-12-23 08:09:43 +00001898 lsp_seqnum_update (lsp);
hassof390d2c2004-09-10 20:48:21 +00001899
Josh Bailey3f045a02012-03-24 08:35:20 -07001900 lsp->last_generated = time (NULL);
1901 lsp_set_all_srmflags (lsp);
1902 for (ALL_LIST_ELEMENTS_RO (lsp->lspu.frags, node, frag))
1903 {
Subbaiah Venkatae38e0df2012-03-27 23:48:05 -07001904 frag->lsp_header->lsp_bits = lsp_bits_generate (level,
Amritha Nambiarc8ee9402015-08-24 16:40:14 -07001905 area->overload_bit,
1906 area->attached_bit);
Josh Bailey3f045a02012-03-24 08:35:20 -07001907 /* Set the lifetime values of all the fragments to the same value,
1908 * so that no fragment expires before the lsp is refreshed.
1909 */
1910 frag->lsp_header->rem_lifetime = htons (rem_lifetime);
1911 lsp_set_all_srmflags (frag);
1912 }
1913
1914 refresh_time = lsp_refresh_time (lsp, rem_lifetime);
1915 if (level == IS_LEVEL_1)
1916 THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
1917 lsp_l1_refresh, area, refresh_time);
1918 else if (level == IS_LEVEL_2)
1919 THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
1920 lsp_l2_refresh, area, refresh_time);
Christian Franke61010c32015-11-10 18:43:34 +01001921 area->lsp_regenerate_pending[level - 1] = 0;
Josh Bailey3f045a02012-03-24 08:35:20 -07001922
hassof390d2c2004-09-10 20:48:21 +00001923 if (isis->debugs & DEBUG_UPDATE_PACKETS)
1924 {
Josh Bailey3f045a02012-03-24 08:35:20 -07001925 zlog_debug ("ISIS-Upd (%s): Refreshing our L%d LSP %s, len %d, "
1926 "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us",
1927 area->area_tag, level,
1928 rawlspid_print (lsp->lsp_header->lsp_id),
1929 ntohl (lsp->lsp_header->pdu_len),
1930 ntohl (lsp->lsp_header->seq_num),
1931 ntohs (lsp->lsp_header->checksum),
1932 ntohs (lsp->lsp_header->rem_lifetime),
1933 refresh_time);
hassof390d2c2004-09-10 20:48:21 +00001934 }
Christian Franke61010c32015-11-10 18:43:34 +01001935 sched_debug("ISIS (%s): Rebuilt L%d LSP. Set triggered regenerate to non-pending.",
1936 area->area_tag, level);
jardineb5d44e2003-12-23 08:09:43 +00001937
jardineb5d44e2003-12-23 08:09:43 +00001938 return ISIS_OK;
1939}
1940
jardineb5d44e2003-12-23 08:09:43 +00001941/*
Josh Bailey3f045a02012-03-24 08:35:20 -07001942 * Something has changed or periodic refresh -> regenerate LSP
jardineb5d44e2003-12-23 08:09:43 +00001943 */
Josh Bailey3f045a02012-03-24 08:35:20 -07001944static int
1945lsp_l1_refresh (struct thread *thread)
jardineb5d44e2003-12-23 08:09:43 +00001946{
1947 struct isis_area *area;
jardineb5d44e2003-12-23 08:09:43 +00001948
1949 area = THREAD_ARG (thread);
1950 assert (area);
hassof390d2c2004-09-10 20:48:21 +00001951
jardineb5d44e2003-12-23 08:09:43 +00001952 area->t_lsp_refresh[0] = NULL;
Josh Bailey3f045a02012-03-24 08:35:20 -07001953 area->lsp_regenerate_pending[0] = 0;
hassof390d2c2004-09-10 20:48:21 +00001954
Josh Bailey3f045a02012-03-24 08:35:20 -07001955 if ((area->is_type & IS_LEVEL_1) == 0)
1956 return ISIS_ERROR;
jardineb5d44e2003-12-23 08:09:43 +00001957
Christian Franke61010c32015-11-10 18:43:34 +01001958 sched_debug("ISIS (%s): LSP L1 refresh timer expired. Refreshing LSP...", area->area_tag);
Josh Bailey3f045a02012-03-24 08:35:20 -07001959 return lsp_regenerate (area, IS_LEVEL_1);
jardineb5d44e2003-12-23 08:09:43 +00001960}
1961
Josh Bailey3f045a02012-03-24 08:35:20 -07001962static int
1963lsp_l2_refresh (struct thread *thread)
jardineb5d44e2003-12-23 08:09:43 +00001964{
1965 struct isis_area *area;
jardineb5d44e2003-12-23 08:09:43 +00001966
1967 area = THREAD_ARG (thread);
1968 assert (area);
hassof390d2c2004-09-10 20:48:21 +00001969
jardineb5d44e2003-12-23 08:09:43 +00001970 area->t_lsp_refresh[1] = NULL;
jardineb5d44e2003-12-23 08:09:43 +00001971 area->lsp_regenerate_pending[1] = 0;
hassof390d2c2004-09-10 20:48:21 +00001972
Josh Bailey3f045a02012-03-24 08:35:20 -07001973 if ((area->is_type & IS_LEVEL_2) == 0)
1974 return ISIS_ERROR;
1975
Christian Franke61010c32015-11-10 18:43:34 +01001976 sched_debug("ISIS (%s): LSP L2 refresh timer expired. Refreshing LSP...", area->area_tag);
Josh Bailey3f045a02012-03-24 08:35:20 -07001977 return lsp_regenerate (area, IS_LEVEL_2);
jardineb5d44e2003-12-23 08:09:43 +00001978}
1979
hassof390d2c2004-09-10 20:48:21 +00001980int
Josh Bailey3f045a02012-03-24 08:35:20 -07001981lsp_regenerate_schedule (struct isis_area *area, int level, int all_pseudo)
jardineb5d44e2003-12-23 08:09:43 +00001982{
1983 struct isis_lsp *lsp;
1984 u_char id[ISIS_SYS_ID_LEN + 2];
1985 time_t now, diff;
Christian Franke61010c32015-11-10 18:43:34 +01001986 long timeout;
Josh Bailey3f045a02012-03-24 08:35:20 -07001987 struct listnode *cnode;
1988 struct isis_circuit *circuit;
1989 int lvl;
1990
1991 if (area == NULL)
1992 return ISIS_ERROR;
1993
Christian Franke61010c32015-11-10 18:43:34 +01001994 sched_debug("ISIS (%s): Scheduling regeneration of %s LSPs, %sincluding PSNs",
1995 area->area_tag, circuit_t2string(level), all_pseudo ? "" : "not ");
1996
hassof390d2c2004-09-10 20:48:21 +00001997 memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
1998 LSP_PSEUDO_ID (id) = LSP_FRAGMENT (id) = 0;
jardineb5d44e2003-12-23 08:09:43 +00001999 now = time (NULL);
Josh Bailey3f045a02012-03-24 08:35:20 -07002000
2001 for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++)
hassof390d2c2004-09-10 20:48:21 +00002002 {
Josh Bailey3f045a02012-03-24 08:35:20 -07002003 if (!((level & lvl) && (area->is_type & lvl)))
2004 continue;
2005
Christian Franke61010c32015-11-10 18:43:34 +01002006 sched_debug("ISIS (%s): Checking whether L%d needs to be scheduled",
2007 area->area_tag, lvl);
2008
Josh Bailey3f045a02012-03-24 08:35:20 -07002009 if (area->lsp_regenerate_pending[lvl - 1])
Christian Franke61010c32015-11-10 18:43:34 +01002010 {
2011 struct timeval remain = thread_timer_remain(area->t_lsp_refresh[lvl - 1]);
2012 sched_debug("ISIS (%s): Regeneration is already pending, nothing todo."
2013 " (Due in %lld.%03lld seconds)", area->area_tag,
2014 (long long)remain.tv_sec, (long long)remain.tv_usec / 1000);
2015 continue;
2016 }
Josh Bailey3f045a02012-03-24 08:35:20 -07002017
2018 lsp = lsp_search (id, area->lspdb[lvl - 1]);
2019 if (!lsp)
Christian Franke61010c32015-11-10 18:43:34 +01002020 {
2021 sched_debug("ISIS (%s): We do not have any LSPs to regenerate, nothing todo.",
2022 area->area_tag);
2023 continue;
2024 }
Josh Bailey3f045a02012-03-24 08:35:20 -07002025
hassof390d2c2004-09-10 20:48:21 +00002026 /*
2027 * Throttle avoidance
2028 */
Christian Franke61010c32015-11-10 18:43:34 +01002029 sched_debug("ISIS (%s): Will schedule regen timer. Last run was: %lld, Now is: %lld",
2030 area->area_tag, (long long)lsp->last_generated, (long long)now);
Josh Bailey3f045a02012-03-24 08:35:20 -07002031 THREAD_TIMER_OFF (area->t_lsp_refresh[lvl - 1]);
hassof390d2c2004-09-10 20:48:21 +00002032 diff = now - lsp->last_generated;
Josh Bailey3f045a02012-03-24 08:35:20 -07002033 if (diff < area->lsp_gen_interval[lvl - 1])
2034 {
Christian Franke61010c32015-11-10 18:43:34 +01002035 timeout = 1000 * (area->lsp_gen_interval[lvl - 1] - diff);
2036 sched_debug("ISIS (%s): Scheduling in %ld ms to match configured lsp_gen_interval",
2037 area->area_tag, timeout);
Josh Bailey3f045a02012-03-24 08:35:20 -07002038 }
hassof390d2c2004-09-10 20:48:21 +00002039 else
Josh Bailey3f045a02012-03-24 08:35:20 -07002040 {
Michael Zinggbe62b172012-10-26 11:18:19 +02002041 /*
2042 * lsps are not regenerated if lsp_regenerate function is called
2043 * directly. However if the lsp_regenerate call is queued for
2044 * later execution it works.
2045 */
Christian Franke61010c32015-11-10 18:43:34 +01002046 timeout = 100;
2047 sched_debug("ISIS (%s): Last generation was more than lsp_gen_interval ago."
2048 " Scheduling for execution in %ld ms.", area->area_tag, timeout);
2049 }
2050
2051 area->lsp_regenerate_pending[lvl - 1] = 1;
2052 if (lvl == IS_LEVEL_1)
2053 {
2054 THREAD_TIMER_MSEC_ON(master, area->t_lsp_refresh[lvl - 1],
2055 lsp_l1_refresh, area, timeout);
2056 }
2057 else if (lvl == IS_LEVEL_2)
2058 {
2059 THREAD_TIMER_MSEC_ON(master, area->t_lsp_refresh[lvl - 1],
2060 lsp_l2_refresh, area, timeout);
Josh Bailey3f045a02012-03-24 08:35:20 -07002061 }
hassof390d2c2004-09-10 20:48:21 +00002062 }
Josh Bailey3f045a02012-03-24 08:35:20 -07002063
2064 if (all_pseudo)
hassof390d2c2004-09-10 20:48:21 +00002065 {
Josh Bailey3f045a02012-03-24 08:35:20 -07002066 for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit))
2067 lsp_regenerate_schedule_pseudo (circuit, level);
hassof390d2c2004-09-10 20:48:21 +00002068 }
2069
2070 return ISIS_OK;
jardineb5d44e2003-12-23 08:09:43 +00002071}
2072
2073/*
2074 * Funcs for pseudonode LSPs
2075 */
2076
2077/*
2078 * 7.3.8 and 7.3.10 Generation of level 1 and 2 pseudonode LSPs
2079 */
hasso92365882005-01-18 13:53:33 +00002080static void
hassof390d2c2004-09-10 20:48:21 +00002081lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit,
2082 int level)
jardineb5d44e2003-12-23 08:09:43 +00002083{
2084 struct isis_adjacency *adj;
2085 struct is_neigh *is_neigh;
hassoaa4376e2005-09-26 17:39:48 +00002086 struct te_is_neigh *te_is_neigh;
jardineb5d44e2003-12-23 08:09:43 +00002087 struct es_neigh *es_neigh;
2088 struct list *adj_list;
hasso3fdb2dd2005-09-28 18:45:54 +00002089 struct listnode *node;
Christian Franke80a8f722015-11-12 14:21:47 +01002090 struct isis_area *area = circuit->area;
2091
2092 lsp_debug("ISIS (%s): Constructing pseudo LSP %s for interface %s level %d",
2093 area->area_tag, rawlspid_print(lsp->lsp_header->lsp_id),
2094 circuit->interface->name, level);
hassof390d2c2004-09-10 20:48:21 +00002095
jardineb5d44e2003-12-23 08:09:43 +00002096 lsp->level = level;
Josh Bailey3f045a02012-03-24 08:35:20 -07002097 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
Amritha Nambiarc8ee9402015-08-24 16:40:14 -07002098 lsp->lsp_header->lsp_bits = lsp_bits_generate (level, 0,
2099 circuit->area->attached_bit);
jardineb5d44e2003-12-23 08:09:43 +00002100
2101 /*
2102 * add self to IS neighbours
2103 */
hassoaa4376e2005-09-26 17:39:48 +00002104 if (circuit->area->oldmetric)
hassof390d2c2004-09-10 20:48:21 +00002105 {
hassoaa4376e2005-09-26 17:39:48 +00002106 if (lsp->tlv_data.is_neighs == NULL)
2107 {
2108 lsp->tlv_data.is_neighs = list_new ();
2109 lsp->tlv_data.is_neighs->del = free_tlv;
2110 }
2111 is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
paul15935e92005-05-03 09:27:23 +00002112
hassoaa4376e2005-09-26 17:39:48 +00002113 memcpy (&is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN);
2114 listnode_add (lsp->tlv_data.is_neighs, is_neigh);
Christian Franke80a8f722015-11-12 14:21:47 +01002115 lsp_debug("ISIS (%s): Adding %s.%02x as old-style neighbor (self)",
2116 area->area_tag, sysid_print(is_neigh->neigh_id),
2117 LSP_PSEUDO_ID(is_neigh->neigh_id));
hassoaa4376e2005-09-26 17:39:48 +00002118 }
2119 if (circuit->area->newmetric)
2120 {
2121 if (lsp->tlv_data.te_is_neighs == NULL)
2122 {
2123 lsp->tlv_data.te_is_neighs = list_new ();
2124 lsp->tlv_data.te_is_neighs->del = free_tlv;
2125 }
2126 te_is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct te_is_neigh));
2127
2128 memcpy (&te_is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN);
2129 listnode_add (lsp->tlv_data.te_is_neighs, te_is_neigh);
Christian Franke80a8f722015-11-12 14:21:47 +01002130 lsp_debug("ISIS (%s): Adding %s.%02x as te-style neighbor (self)",
2131 area->area_tag, sysid_print(te_is_neigh->neigh_id),
2132 LSP_PSEUDO_ID(te_is_neigh->neigh_id));
hassoaa4376e2005-09-26 17:39:48 +00002133 }
hassof390d2c2004-09-10 20:48:21 +00002134
2135 adj_list = list_new ();
2136 isis_adj_build_up_list (circuit->u.bc.adjdb[level - 1], adj_list);
2137
hasso3fdb2dd2005-09-28 18:45:54 +00002138 for (ALL_LIST_ELEMENTS_RO (adj_list, node, adj))
hassof390d2c2004-09-10 20:48:21 +00002139 {
Josh Bailey3f045a02012-03-24 08:35:20 -07002140 if (adj->level & level)
hassof390d2c2004-09-10 20:48:21 +00002141 {
Josh Bailey3f045a02012-03-24 08:35:20 -07002142 if ((level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_L1_IS) ||
2143 (level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_L2_IS &&
hassoaa4376e2005-09-26 17:39:48 +00002144 adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||
Josh Bailey3f045a02012-03-24 08:35:20 -07002145 (level == IS_LEVEL_2 && adj->sys_type == ISIS_SYSTYPE_L2_IS))
hassof390d2c2004-09-10 20:48:21 +00002146 {
2147 /* an IS neighbour -> add it */
hassoaa4376e2005-09-26 17:39:48 +00002148 if (circuit->area->oldmetric)
2149 {
2150 is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
paul15935e92005-05-03 09:27:23 +00002151
hassoaa4376e2005-09-26 17:39:48 +00002152 memcpy (&is_neigh->neigh_id, adj->sysid, ISIS_SYS_ID_LEN);
2153 listnode_add (lsp->tlv_data.is_neighs, is_neigh);
Christian Franke80a8f722015-11-12 14:21:47 +01002154 lsp_debug("ISIS (%s): Adding %s.%02x as old-style neighbor (peer)",
2155 area->area_tag, sysid_print(is_neigh->neigh_id),
2156 LSP_PSEUDO_ID(is_neigh->neigh_id));
hassoaa4376e2005-09-26 17:39:48 +00002157 }
2158 if (circuit->area->newmetric)
2159 {
2160 te_is_neigh = XCALLOC (MTYPE_ISIS_TLV,
2161 sizeof (struct te_is_neigh));
2162 memcpy (&te_is_neigh->neigh_id, adj->sysid, ISIS_SYS_ID_LEN);
2163 listnode_add (lsp->tlv_data.te_is_neighs, te_is_neigh);
Christian Franke80a8f722015-11-12 14:21:47 +01002164 lsp_debug("ISIS (%s): Adding %s.%02x as te-style neighbor (peer)",
2165 area->area_tag, sysid_print(te_is_neigh->neigh_id),
2166 LSP_PSEUDO_ID(te_is_neigh->neigh_id));
hassoaa4376e2005-09-26 17:39:48 +00002167 }
hassof390d2c2004-09-10 20:48:21 +00002168 }
Josh Bailey3f045a02012-03-24 08:35:20 -07002169 else if (level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_ES)
hassof390d2c2004-09-10 20:48:21 +00002170 {
2171 /* an ES neigbour add it, if we are building level 1 LSP */
2172 /* FIXME: the tlv-format is hard to use here */
2173 if (lsp->tlv_data.es_neighs == NULL)
2174 {
2175 lsp->tlv_data.es_neighs = list_new ();
2176 lsp->tlv_data.es_neighs->del = free_tlv;
2177 }
paul15935e92005-05-03 09:27:23 +00002178 es_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct es_neigh));
2179
hassof390d2c2004-09-10 20:48:21 +00002180 memcpy (&es_neigh->first_es_neigh, adj->sysid, ISIS_SYS_ID_LEN);
hassoaac372f2005-09-01 17:52:33 +00002181 listnode_add (lsp->tlv_data.es_neighs, es_neigh);
Christian Franke80a8f722015-11-12 14:21:47 +01002182 lsp_debug("ISIS (%s): Adding %s as ES neighbor (peer)",
2183 area->area_tag, sysid_print(es_neigh->first_es_neigh));
hassof390d2c2004-09-10 20:48:21 +00002184 }
Christian Franke80a8f722015-11-12 14:21:47 +01002185 else
2186 {
2187 lsp_debug("ISIS (%s): Ignoring neighbor %s, level does not match",
2188 area->area_tag, sysid_print(adj->sysid));
2189 }
2190 }
2191 else
2192 {
2193 lsp_debug("ISIS (%s): Ignoring neighbor %s, level does not intersect",
2194 area->area_tag, sysid_print(adj->sysid));
hassof390d2c2004-09-10 20:48:21 +00002195 }
jardineb5d44e2003-12-23 08:09:43 +00002196 }
Josh Bailey3f045a02012-03-24 08:35:20 -07002197 list_delete (adj_list);
hassof390d2c2004-09-10 20:48:21 +00002198
Christian Franke80a8f722015-11-12 14:21:47 +01002199 lsp_debug("ISIS (%s): Pseudo LSP construction is complete.", area->area_tag);
2200
hassoc0fb2a52005-09-03 16:29:40 +00002201 /* Reset endp of stream to overwrite only TLV part of it. */
hassoc89c05d2005-09-04 21:36:36 +00002202 stream_reset (lsp->pdu);
hassoc0fb2a52005-09-03 16:29:40 +00002203 stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
2204
jardineb5d44e2003-12-23 08:09:43 +00002205 /*
2206 * Add the authentication info if it's present
2207 */
Josh Bailey3f045a02012-03-24 08:35:20 -07002208 lsp_auth_add (lsp);
jardineb5d44e2003-12-23 08:09:43 +00002209
2210 if (lsp->tlv_data.is_neighs && listcount (lsp->tlv_data.is_neighs) > 0)
2211 tlv_add_is_neighs (lsp->tlv_data.is_neighs, lsp->pdu);
2212
hassoaa4376e2005-09-26 17:39:48 +00002213 if (lsp->tlv_data.te_is_neighs && listcount (lsp->tlv_data.te_is_neighs) > 0)
2214 tlv_add_te_is_neighs (lsp->tlv_data.te_is_neighs, lsp->pdu);
2215
jardineb5d44e2003-12-23 08:09:43 +00002216 if (lsp->tlv_data.es_neighs && listcount (lsp->tlv_data.es_neighs) > 0)
2217 tlv_add_is_neighs (lsp->tlv_data.es_neighs, lsp->pdu);
2218
paul9985f832005-02-09 15:51:56 +00002219 lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
hassof390d2c2004-09-10 20:48:21 +00002220
Josh Bailey3f045a02012-03-24 08:35:20 -07002221 /* Recompute authentication and checksum information */
2222 lsp_auth_update (lsp);
2223 fletcher_checksum(STREAM_DATA (lsp->pdu) + 12,
2224 ntohs (lsp->lsp_header->pdu_len) - 12, 12);
jardineb5d44e2003-12-23 08:09:43 +00002225
2226 return;
2227}
2228
Josh Bailey3f045a02012-03-24 08:35:20 -07002229int
2230lsp_generate_pseudo (struct isis_circuit *circuit, int level)
jardineb5d44e2003-12-23 08:09:43 +00002231{
2232 dict_t *lspdb = circuit->area->lspdb[level - 1];
2233 struct isis_lsp *lsp;
2234 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
Josh Bailey3f045a02012-03-24 08:35:20 -07002235 u_int16_t rem_lifetime, refresh_time;
2236
2237 if ((circuit->is_type & level) != level ||
2238 (circuit->state != C_STATE_UP) ||
2239 (circuit->circ_type != CIRCUIT_T_BROADCAST) ||
2240 (circuit->u.bc.is_dr[level - 1] == 0))
2241 return ISIS_ERROR;
2242
2243 memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
2244 LSP_FRAGMENT (lsp_id) = 0;
2245 LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id;
2246
2247 /*
2248 * If for some reason have a pseudo LSP in the db already -> regenerate
2249 */
2250 if (lsp_search (lsp_id, lspdb))
2251 return lsp_regenerate_schedule_pseudo (circuit, level);
2252
2253 rem_lifetime = lsp_rem_lifetime (circuit->area, level);
2254 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
Christian Frankef1fc1db2015-11-10 18:43:31 +01002255 lsp = lsp_new (circuit->area, lsp_id, rem_lifetime, 1,
Amritha Nambiarc8ee9402015-08-24 16:40:14 -07002256 circuit->area->is_type | circuit->area->attached_bit,
2257 0, level);
Josh Bailey3f045a02012-03-24 08:35:20 -07002258 lsp->area = circuit->area;
2259
2260 lsp_build_pseudo (lsp, circuit, level);
2261
2262 lsp->own_lsp = 1;
2263 lsp_insert (lsp, lspdb);
2264 lsp_set_all_srmflags (lsp);
2265
2266 refresh_time = lsp_refresh_time (lsp, rem_lifetime);
2267 THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
2268 circuit->lsp_regenerate_pending[level - 1] = 0;
2269 if (level == IS_LEVEL_1)
2270 THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1],
2271 lsp_l1_refresh_pseudo, circuit, refresh_time);
2272 else if (level == IS_LEVEL_2)
2273 THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1],
2274 lsp_l2_refresh_pseudo, circuit, refresh_time);
2275
2276 if (isis->debugs & DEBUG_UPDATE_PACKETS)
2277 {
2278 zlog_debug ("ISIS-Upd (%s): Building L%d Pseudo LSP %s, len %d, "
2279 "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us",
2280 circuit->area->area_tag, level,
2281 rawlspid_print (lsp->lsp_header->lsp_id),
2282 ntohl (lsp->lsp_header->pdu_len),
2283 ntohl (lsp->lsp_header->seq_num),
2284 ntohs (lsp->lsp_header->checksum),
2285 ntohs (lsp->lsp_header->rem_lifetime),
2286 refresh_time);
2287 }
2288
2289 return ISIS_OK;
2290}
2291
2292static int
2293lsp_regenerate_pseudo (struct isis_circuit *circuit, int level)
2294{
2295 dict_t *lspdb = circuit->area->lspdb[level - 1];
2296 struct isis_lsp *lsp;
2297 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
2298 u_int16_t rem_lifetime, refresh_time;
2299
2300 if ((circuit->is_type & level) != level ||
2301 (circuit->state != C_STATE_UP) ||
2302 (circuit->circ_type != CIRCUIT_T_BROADCAST) ||
2303 (circuit->u.bc.is_dr[level - 1] == 0))
2304 return ISIS_ERROR;
hassof390d2c2004-09-10 20:48:21 +00002305
jardineb5d44e2003-12-23 08:09:43 +00002306 memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
hassof390d2c2004-09-10 20:48:21 +00002307 LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id;
2308 LSP_FRAGMENT (lsp_id) = 0;
2309
jardineb5d44e2003-12-23 08:09:43 +00002310 lsp = lsp_search (lsp_id, lspdb);
hassof390d2c2004-09-10 20:48:21 +00002311
2312 if (!lsp)
2313 {
Josh Bailey3f045a02012-03-24 08:35:20 -07002314 zlog_err ("lsp_regenerate_pseudo: no l%d LSP %s found!",
2315 level, rawlspid_print (lsp_id));
hassof390d2c2004-09-10 20:48:21 +00002316 return ISIS_ERROR;
2317 }
2318 lsp_clear_data (lsp);
jardineb5d44e2003-12-23 08:09:43 +00002319
2320 lsp_build_pseudo (lsp, circuit, level);
2321
Josh Bailey3f045a02012-03-24 08:35:20 -07002322 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
Amritha Nambiarc8ee9402015-08-24 16:40:14 -07002323 lsp->lsp_header->lsp_bits = lsp_bits_generate (level, 0,
2324 circuit->area->attached_bit);
Josh Bailey3f045a02012-03-24 08:35:20 -07002325 rem_lifetime = lsp_rem_lifetime (circuit->area, level);
2326 lsp->lsp_header->rem_lifetime = htons (rem_lifetime);
jardineb5d44e2003-12-23 08:09:43 +00002327 lsp_inc_seqnum (lsp, 0);
Josh Bailey3f045a02012-03-24 08:35:20 -07002328 lsp->last_generated = time (NULL);
2329 lsp_set_all_srmflags (lsp);
2330
2331 refresh_time = lsp_refresh_time (lsp, rem_lifetime);
2332 if (level == IS_LEVEL_1)
2333 THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1],
2334 lsp_l1_refresh_pseudo, circuit, refresh_time);
2335 else if (level == IS_LEVEL_2)
2336 THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1],
2337 lsp_l2_refresh_pseudo, circuit, refresh_time);
hassof390d2c2004-09-10 20:48:21 +00002338
2339 if (isis->debugs & DEBUG_UPDATE_PACKETS)
2340 {
Josh Bailey3f045a02012-03-24 08:35:20 -07002341 zlog_debug ("ISIS-Upd (%s): Refreshing L%d Pseudo LSP %s, len %d, "
2342 "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us",
2343 circuit->area->area_tag, level,
2344 rawlspid_print (lsp->lsp_header->lsp_id),
2345 ntohl (lsp->lsp_header->pdu_len),
2346 ntohl (lsp->lsp_header->seq_num),
2347 ntohs (lsp->lsp_header->checksum),
2348 ntohs (lsp->lsp_header->rem_lifetime),
2349 refresh_time);
hassof390d2c2004-09-10 20:48:21 +00002350 }
jardineb5d44e2003-12-23 08:09:43 +00002351
jardineb5d44e2003-12-23 08:09:43 +00002352 return ISIS_OK;
2353}
2354
Josh Bailey3f045a02012-03-24 08:35:20 -07002355/*
2356 * Something has changed or periodic refresh -> regenerate pseudo LSP
2357 */
2358static int
jardineb5d44e2003-12-23 08:09:43 +00002359lsp_l1_refresh_pseudo (struct thread *thread)
2360{
2361 struct isis_circuit *circuit;
Josh Bailey3f045a02012-03-24 08:35:20 -07002362 u_char id[ISIS_SYS_ID_LEN + 2];
jardineb5d44e2003-12-23 08:09:43 +00002363
hassof390d2c2004-09-10 20:48:21 +00002364 circuit = THREAD_ARG (thread);
2365
hasso13c48f72004-09-10 21:19:13 +00002366 circuit->u.bc.t_refresh_pseudo_lsp[0] = NULL;
Josh Bailey3f045a02012-03-24 08:35:20 -07002367 circuit->lsp_regenerate_pending[0] = 0;
hasso13c48f72004-09-10 21:19:13 +00002368
Josh Bailey3f045a02012-03-24 08:35:20 -07002369 if ((circuit->u.bc.is_dr[0] == 0) ||
2370 (circuit->is_type & IS_LEVEL_1) == 0)
2371 {
2372 memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
2373 LSP_PSEUDO_ID (id) = circuit->circuit_id;
2374 LSP_FRAGMENT (id) = 0;
2375 lsp_purge_pseudo (id, circuit, IS_LEVEL_1);
2376 return ISIS_ERROR;
2377 }
hassof390d2c2004-09-10 20:48:21 +00002378
Josh Bailey3f045a02012-03-24 08:35:20 -07002379 return lsp_regenerate_pseudo (circuit, IS_LEVEL_1);
jardineb5d44e2003-12-23 08:09:43 +00002380}
2381
Josh Bailey3f045a02012-03-24 08:35:20 -07002382static int
jardineb5d44e2003-12-23 08:09:43 +00002383lsp_l2_refresh_pseudo (struct thread *thread)
2384{
2385 struct isis_circuit *circuit;
Josh Bailey3f045a02012-03-24 08:35:20 -07002386 u_char id[ISIS_SYS_ID_LEN + 2];
2387
hassof390d2c2004-09-10 20:48:21 +00002388 circuit = THREAD_ARG (thread);
2389
hasso13c48f72004-09-10 21:19:13 +00002390 circuit->u.bc.t_refresh_pseudo_lsp[1] = NULL;
Josh Bailey3f045a02012-03-24 08:35:20 -07002391 circuit->lsp_regenerate_pending[1] = 0;
hasso13c48f72004-09-10 21:19:13 +00002392
Josh Bailey3f045a02012-03-24 08:35:20 -07002393 if ((circuit->u.bc.is_dr[1] == 0) ||
2394 (circuit->is_type & IS_LEVEL_2) == 0)
2395 {
2396 memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
2397 LSP_PSEUDO_ID (id) = circuit->circuit_id;
2398 LSP_FRAGMENT (id) = 0;
2399 lsp_purge_pseudo (id, circuit, IS_LEVEL_2);
2400 return ISIS_ERROR;
2401 }
jardineb5d44e2003-12-23 08:09:43 +00002402
Josh Bailey3f045a02012-03-24 08:35:20 -07002403 return lsp_regenerate_pseudo (circuit, IS_LEVEL_2);
jardineb5d44e2003-12-23 08:09:43 +00002404}
2405
hassof390d2c2004-09-10 20:48:21 +00002406int
Josh Bailey3f045a02012-03-24 08:35:20 -07002407lsp_regenerate_schedule_pseudo (struct isis_circuit *circuit, int level)
jardineb5d44e2003-12-23 08:09:43 +00002408{
2409 struct isis_lsp *lsp;
Josh Bailey3f045a02012-03-24 08:35:20 -07002410 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
2411 time_t now, diff;
Christian Franke61010c32015-11-10 18:43:34 +01002412 long timeout;
Josh Bailey3f045a02012-03-24 08:35:20 -07002413 int lvl;
Christian Franke61010c32015-11-10 18:43:34 +01002414 struct isis_area *area = circuit->area;
jardineb5d44e2003-12-23 08:09:43 +00002415
Josh Bailey3f045a02012-03-24 08:35:20 -07002416 if (circuit == NULL ||
2417 circuit->circ_type != CIRCUIT_T_BROADCAST ||
2418 circuit->state != C_STATE_UP)
2419 return ISIS_OK;
jardineb5d44e2003-12-23 08:09:43 +00002420
Christian Franke61010c32015-11-10 18:43:34 +01002421 sched_debug("ISIS (%s): Scheduling regeneration of %s pseudo LSP for interface %s",
2422 area->area_tag, circuit_t2string(level), circuit->interface->name);
2423
Josh Bailey3f045a02012-03-24 08:35:20 -07002424 memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
2425 LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id;
2426 LSP_FRAGMENT (lsp_id) = 0;
2427 now = time (NULL);
jardineb5d44e2003-12-23 08:09:43 +00002428
Josh Bailey3f045a02012-03-24 08:35:20 -07002429 for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++)
2430 {
Christian Franke61010c32015-11-10 18:43:34 +01002431 sched_debug("ISIS (%s): Checking whether L%d pseudo LSP needs to be scheduled",
2432 area->area_tag, lvl);
jardineb5d44e2003-12-23 08:09:43 +00002433
Christian Franke61010c32015-11-10 18:43:34 +01002434 if (!((level & lvl) && (circuit->is_type & lvl)))
2435 {
2436 sched_debug("ISIS (%s): Level is not active on circuit",
2437 area->area_tag);
2438 continue;
2439 }
2440
2441 if (circuit->u.bc.is_dr[lvl - 1] == 0)
2442 {
2443 sched_debug("ISIS (%s): This IS is not DR, nothing to do.",
2444 area->area_tag);
2445 continue;
2446 }
2447
2448 if (circuit->lsp_regenerate_pending[lvl - 1])
2449 {
2450 struct timeval remain =
2451 thread_timer_remain(circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
2452 sched_debug("ISIS (%s): Regenerate is already pending, nothing todo."
2453 " (Due in %lld.%03lld seconds)", area->area_tag,
2454 (long long)remain.tv_sec, (long long)remain.tv_usec/1000);
2455 continue;
2456 }
hassof390d2c2004-09-10 20:48:21 +00002457
Josh Bailey3f045a02012-03-24 08:35:20 -07002458 lsp = lsp_search (lsp_id, circuit->area->lspdb[lvl - 1]);
2459 if (!lsp)
Christian Franke61010c32015-11-10 18:43:34 +01002460 {
2461 sched_debug("ISIS (%s): Pseudonode LSP does not exist yet, nothing to regenerate.",
2462 area->area_tag);
2463 continue;
2464 }
jardineb5d44e2003-12-23 08:09:43 +00002465
Josh Bailey3f045a02012-03-24 08:35:20 -07002466 /*
2467 * Throttle avoidance
2468 */
Christian Franke61010c32015-11-10 18:43:34 +01002469 sched_debug("ISIS (%s): Will schedule PSN regen timer. Last run was: %lld, Now is: %lld",
2470 area->area_tag, (long long)lsp->last_generated, (long long) now);
Josh Bailey3f045a02012-03-24 08:35:20 -07002471 THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
2472 diff = now - lsp->last_generated;
2473 if (diff < circuit->area->lsp_gen_interval[lvl - 1])
2474 {
Christian Franke61010c32015-11-10 18:43:34 +01002475 timeout = 1000 * (circuit->area->lsp_gen_interval[lvl - 1] - diff);
2476 sched_debug("ISIS (%s): Sechduling in %ld ms to match configured lsp_gen_interval",
2477 area->area_tag, timeout);
Josh Bailey3f045a02012-03-24 08:35:20 -07002478 }
2479 else
2480 {
Christian Franke61010c32015-11-10 18:43:34 +01002481 timeout = 100;
2482 sched_debug("ISIS (%s): Last generation was more than lsp_gen_interval ago."
2483 " Scheduling for execution in %ld ms.", area->area_tag, timeout);
2484 }
2485
2486 circuit->lsp_regenerate_pending[lvl - 1] = 1;
2487
2488 if (lvl == IS_LEVEL_1)
2489 {
2490 THREAD_TIMER_MSEC_ON(master,
2491 circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1],
2492 lsp_l1_refresh_pseudo, circuit, timeout);
2493 }
2494 else if (lvl == IS_LEVEL_2)
2495 {
2496 THREAD_TIMER_MSEC_ON(master,
2497 circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1],
2498 lsp_l2_refresh_pseudo, circuit, timeout);
Josh Bailey3f045a02012-03-24 08:35:20 -07002499 }
2500 }
jardineb5d44e2003-12-23 08:09:43 +00002501
Josh Bailey3f045a02012-03-24 08:35:20 -07002502 return ISIS_OK;
jardineb5d44e2003-12-23 08:09:43 +00002503}
2504
jardineb5d44e2003-12-23 08:09:43 +00002505/*
2506 * Walk through LSPs for an area
2507 * - set remaining lifetime
2508 * - set LSPs with SRMflag set for sending
2509 */
hassof390d2c2004-09-10 20:48:21 +00002510int
jardineb5d44e2003-12-23 08:09:43 +00002511lsp_tick (struct thread *thread)
2512{
2513 struct isis_area *area;
2514 struct isis_circuit *circuit;
2515 struct isis_lsp *lsp;
2516 struct list *lsp_list;
hasso3fdb2dd2005-09-28 18:45:54 +00002517 struct listnode *lspnode, *cnode;
jardineb5d44e2003-12-23 08:09:43 +00002518 dnode_t *dnode, *dnode_next;
2519 int level;
Josh Bailey3f045a02012-03-24 08:35:20 -07002520 u_int16_t rem_lifetime;
jardineb5d44e2003-12-23 08:09:43 +00002521
2522 lsp_list = list_new ();
hassof390d2c2004-09-10 20:48:21 +00002523
jardineb5d44e2003-12-23 08:09:43 +00002524 area = THREAD_ARG (thread);
2525 assert (area);
hasso13c48f72004-09-10 21:19:13 +00002526 area->t_tick = NULL;
hassof390d2c2004-09-10 20:48:21 +00002527 THREAD_TIMER_ON (master, area->t_tick, lsp_tick, area, 1);
jardineb5d44e2003-12-23 08:09:43 +00002528
2529 /*
2530 * Build a list of LSPs with (any) SRMflag set
2531 * and removed the ones that have aged out
2532 */
hassof390d2c2004-09-10 20:48:21 +00002533 for (level = 0; level < ISIS_LEVELS; level++)
2534 {
2535 if (area->lspdb[level] && dict_count (area->lspdb[level]) > 0)
Josh Bailey3f045a02012-03-24 08:35:20 -07002536 {
2537 for (dnode = dict_first (area->lspdb[level]);
2538 dnode != NULL; dnode = dnode_next)
2539 {
2540 dnode_next = dict_next (area->lspdb[level], dnode);
2541 lsp = dnode_get (dnode);
jardineb5d44e2003-12-23 08:09:43 +00002542
Josh Bailey3f045a02012-03-24 08:35:20 -07002543 /*
2544 * The lsp rem_lifetime is kept at 0 for MaxAge or
2545 * ZeroAgeLifetime depending on explicit purge or
2546 * natural age out. So schedule spf only once when
2547 * the first time rem_lifetime becomes 0.
2548 */
2549 rem_lifetime = ntohs(lsp->lsp_header->rem_lifetime);
2550 lsp_set_time (lsp);
2551
2552 /*
2553 * Schedule may run spf which should be done only after
2554 * the lsp rem_lifetime becomes 0 for the first time.
2555 * ISO 10589 - 7.3.16.4 first paragraph.
2556 */
2557 if (rem_lifetime == 1 && lsp->lsp_header->seq_num != 0)
2558 {
2559 /* 7.3.16.4 a) set SRM flags on all */
2560 lsp_set_all_srmflags (lsp);
2561 /* 7.3.16.4 b) retain only the header FIXME */
2562 /* 7.3.16.4 c) record the time to purge FIXME */
2563 /* run/schedule spf */
2564 /* isis_spf_schedule is called inside lsp_destroy() below;
2565 * so it is not needed here. */
2566 /* isis_spf_schedule (lsp->area, lsp->level); */
2567 }
2568
2569 if (lsp->age_out == 0)
2570 {
2571 zlog_debug ("ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out",
2572 area->area_tag,
2573 lsp->level,
2574 rawlspid_print (lsp->lsp_header->lsp_id),
2575 ntohl (lsp->lsp_header->seq_num));
hassof1082d12005-09-19 04:23:34 +00002576#ifdef TOPOLOGY_GENERATE
Josh Bailey3f045a02012-03-24 08:35:20 -07002577 if (lsp->from_topology)
2578 THREAD_TIMER_OFF (lsp->t_lsp_top_ref);
hassof1082d12005-09-19 04:23:34 +00002579#endif /* TOPOLOGY_GENERATE */
Josh Bailey3f045a02012-03-24 08:35:20 -07002580 lsp_destroy (lsp);
2581 lsp = NULL;
2582 dict_delete_free (area->lspdb[level], dnode);
2583 }
2584 else if (flags_any_set (lsp->SRMflags))
2585 listnode_add (lsp_list, lsp);
2586 }
jardineb5d44e2003-12-23 08:09:43 +00002587
Josh Bailey3f045a02012-03-24 08:35:20 -07002588 /*
2589 * Send LSPs on circuits indicated by the SRMflags
2590 */
2591 if (listcount (lsp_list) > 0)
2592 {
paul1eb8ef22005-04-07 07:30:20 +00002593 for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit))
Josh Bailey3f045a02012-03-24 08:35:20 -07002594 {
2595 int diff = time (NULL) - circuit->lsp_queue_last_cleared;
2596 if (circuit->lsp_queue == NULL ||
2597 diff < MIN_LSP_TRANS_INTERVAL)
2598 continue;
hasso3fdb2dd2005-09-28 18:45:54 +00002599 for (ALL_LIST_ELEMENTS_RO (lsp_list, lspnode, lsp))
Josh Bailey3f045a02012-03-24 08:35:20 -07002600 {
2601 if (circuit->upadjcount[lsp->level - 1] &&
2602 ISIS_CHECK_FLAG (lsp->SRMflags, circuit))
2603 {
2604 /* Add the lsp only if it is not already in lsp
2605 * queue */
2606 if (! listnode_lookup (circuit->lsp_queue, lsp))
2607 {
2608 listnode_add (circuit->lsp_queue, lsp);
2609 thread_add_event (master, send_lsp, circuit, 0);
2610 }
2611 }
2612 }
2613 }
2614 list_delete_all_node (lsp_list);
2615 }
2616 }
jardineb5d44e2003-12-23 08:09:43 +00002617 }
jardineb5d44e2003-12-23 08:09:43 +00002618
2619 list_delete (lsp_list);
2620
2621 return ISIS_OK;
2622}
2623
jardineb5d44e2003-12-23 08:09:43 +00002624void
Josh Bailey3f045a02012-03-24 08:35:20 -07002625lsp_purge_pseudo (u_char * id, struct isis_circuit *circuit, int level)
jardineb5d44e2003-12-23 08:09:43 +00002626{
2627 struct isis_lsp *lsp;
Josh Bailey3f045a02012-03-24 08:35:20 -07002628 u_int16_t seq_num;
2629 u_int8_t lsp_bits;
hassof390d2c2004-09-10 20:48:21 +00002630
jardineb5d44e2003-12-23 08:09:43 +00002631 lsp = lsp_search (id, circuit->area->lspdb[level - 1]);
Josh Bailey3f045a02012-03-24 08:35:20 -07002632 if (!lsp)
2633 return;
hassof390d2c2004-09-10 20:48:21 +00002634
Josh Bailey3f045a02012-03-24 08:35:20 -07002635 /* store old values */
2636 seq_num = lsp->lsp_header->seq_num;
2637 lsp_bits = lsp->lsp_header->lsp_bits;
2638
2639 /* reset stream */
2640 lsp_clear_data (lsp);
2641 stream_reset (lsp->pdu);
2642
2643 /* update header */
2644 lsp->lsp_header->pdu_len = htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
2645 memcpy (lsp->lsp_header->lsp_id, id, ISIS_SYS_ID_LEN + 2);
2646 lsp->lsp_header->checksum = 0;
2647 lsp->lsp_header->seq_num = seq_num;
2648 lsp->lsp_header->rem_lifetime = 0;
2649 lsp->lsp_header->lsp_bits = lsp_bits;
2650 lsp->level = level;
2651 lsp->age_out = lsp->area->max_lsp_lifetime[level-1];
2652 stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
2653
2654 /*
2655 * Add and update the authentication info if its present
2656 */
2657 lsp_auth_add (lsp);
2658 lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
2659 lsp_auth_update (lsp);
2660 fletcher_checksum(STREAM_DATA (lsp->pdu) + 12,
2661 ntohs (lsp->lsp_header->pdu_len) - 12, 12);
2662
2663 lsp_set_all_srmflags (lsp);
hassof390d2c2004-09-10 20:48:21 +00002664
jardineb5d44e2003-12-23 08:09:43 +00002665 return;
2666}
2667
2668/*
2669 * Purge own LSP that is received and we don't have.
2670 * -> Do as in 7.3.16.4
2671 */
2672void
Christian Franke749e87a2015-11-10 18:21:44 +01002673lsp_purge_non_exist (int level,
2674 struct isis_link_state_hdr *lsp_hdr,
hassof390d2c2004-09-10 20:48:21 +00002675 struct isis_area *area)
jardineb5d44e2003-12-23 08:09:43 +00002676{
2677 struct isis_lsp *lsp;
2678
2679 /*
2680 * We need to create the LSP to be purged
2681 */
hassoaac372f2005-09-01 17:52:33 +00002682 lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp));
Josh Bailey3f045a02012-03-24 08:35:20 -07002683 lsp->area = area;
Christian Franke749e87a2015-11-10 18:21:44 +01002684 lsp->level = level;
Christian Frankef1fc1db2015-11-10 18:43:31 +01002685 lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu);
hassof390d2c2004-09-10 20:48:21 +00002686 lsp->isis_header = (struct isis_fixed_hdr *) STREAM_DATA (lsp->pdu);
Josh Bailey3f045a02012-03-24 08:35:20 -07002687 fill_fixed_hdr (lsp->isis_header, (lsp->level == IS_LEVEL_1) ? L1_LINK_STATE
hassof390d2c2004-09-10 20:48:21 +00002688 : L2_LINK_STATE);
2689 lsp->lsp_header = (struct isis_link_state_hdr *) (STREAM_DATA (lsp->pdu) +
2690 ISIS_FIXED_HDR_LEN);
jardineb5d44e2003-12-23 08:09:43 +00002691 memcpy (lsp->lsp_header, lsp_hdr, ISIS_LSP_HDR_LEN);
Josh Bailey3f045a02012-03-24 08:35:20 -07002692 stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
hassof390d2c2004-09-10 20:48:21 +00002693
jardineb5d44e2003-12-23 08:09:43 +00002694 /*
jardineb5d44e2003-12-23 08:09:43 +00002695 * Set the remaining lifetime to 0
2696 */
2697 lsp->lsp_header->rem_lifetime = 0;
Josh Bailey3f045a02012-03-24 08:35:20 -07002698
2699 /*
2700 * Add and update the authentication info if its present
2701 */
2702 lsp_auth_add (lsp);
2703 lsp_auth_update (lsp);
2704
2705 /*
2706 * Update the PDU length to header plus any authentication TLV.
2707 */
2708 lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
2709
jardineb5d44e2003-12-23 08:09:43 +00002710 /*
2711 * Put the lsp into LSPdb
2712 */
hassof390d2c2004-09-10 20:48:21 +00002713 lsp_insert (lsp, area->lspdb[lsp->level - 1]);
jardineb5d44e2003-12-23 08:09:43 +00002714
2715 /*
2716 * Send in to whole area
2717 */
Josh Bailey3f045a02012-03-24 08:35:20 -07002718 lsp_set_all_srmflags (lsp);
hassof390d2c2004-09-10 20:48:21 +00002719
jardineb5d44e2003-12-23 08:09:43 +00002720 return;
2721}
2722
Josh Bailey3f045a02012-03-24 08:35:20 -07002723void lsp_set_all_srmflags (struct isis_lsp *lsp)
2724{
2725 struct listnode *node;
2726 struct isis_circuit *circuit;
2727
2728 assert (lsp);
2729
2730 ISIS_FLAGS_CLEAR_ALL(lsp->SRMflags);
2731
2732 if (lsp->area)
2733 {
2734 struct list *circuit_list = lsp->area->circuit_list;
2735 for (ALL_LIST_ELEMENTS_RO (circuit_list, node, circuit))
2736 {
2737 ISIS_SET_FLAG(lsp->SRMflags, circuit);
2738 }
2739 }
2740}
2741
jardineb5d44e2003-12-23 08:09:43 +00002742#ifdef TOPOLOGY_GENERATE
hasso92365882005-01-18 13:53:33 +00002743static int
jardineb5d44e2003-12-23 08:09:43 +00002744top_lsp_refresh (struct thread *thread)
2745{
hassof390d2c2004-09-10 20:48:21 +00002746 struct isis_lsp *lsp;
David Lamparterf50ee932015-03-04 07:13:38 +01002747 u_int16_t rem_lifetime;
jardineb5d44e2003-12-23 08:09:43 +00002748
2749 lsp = THREAD_ARG (thread);
2750 assert (lsp);
2751
2752 lsp->t_lsp_top_ref = NULL;
2753
hassof1082d12005-09-19 04:23:34 +00002754 lsp_seqnum_update (lsp);
jardineb5d44e2003-12-23 08:09:43 +00002755
Josh Bailey3f045a02012-03-24 08:35:20 -07002756 lsp_set_all_srmflags (lsp);
hassof390d2c2004-09-10 20:48:21 +00002757 if (isis->debugs & DEBUG_UPDATE_PACKETS)
2758 {
hasso529d65b2004-12-24 00:14:50 +00002759 zlog_debug ("ISIS-Upd (): refreshing Topology L1 %s",
2760 rawlspid_print (lsp->lsp_header->lsp_id));
hassof390d2c2004-09-10 20:48:21 +00002761 }
hassod3d74742005-09-28 18:30:51 +00002762 /* Refresh dynamic hostname in the cache. */
2763 isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname,
2764 IS_LEVEL_1);
2765
David Lampartera47c5832012-06-21 09:55:38 +02002766 lsp->lsp_header->lsp_bits = lsp_bits_generate (lsp->level,
Amritha Nambiarc8ee9402015-08-24 16:40:14 -07002767 lsp->area->overload_bit,
2768 lsp->area->attached_bit);
Josh Bailey3f045a02012-03-24 08:35:20 -07002769 rem_lifetime = lsp_rem_lifetime (lsp->area, IS_LEVEL_1);
2770 lsp->lsp_header->rem_lifetime = htons (rem_lifetime);
jardineb5d44e2003-12-23 08:09:43 +00002771
David Lamparterf50ee932015-03-04 07:13:38 +01002772 /* refresh_time = lsp_refresh_time (lsp, rem_lifetime); */
hassof390d2c2004-09-10 20:48:21 +00002773 THREAD_TIMER_ON (master, lsp->t_lsp_top_ref, top_lsp_refresh, lsp,
Josh Bailey3f045a02012-03-24 08:35:20 -07002774 lsp->area->lsp_refresh[0]);
jardineb5d44e2003-12-23 08:09:43 +00002775
2776 return ISIS_OK;
2777}
2778
2779void
2780generate_topology_lsps (struct isis_area *area)
2781{
2782 struct listnode *node;
2783 int i, max = 0;
2784 struct arc *arc;
2785 u_char lspid[ISIS_SYS_ID_LEN + 2];
2786 struct isis_lsp *lsp;
Josh Bailey3f045a02012-03-24 08:35:20 -07002787 u_int16_t rem_lifetime, refresh_time;
jardineb5d44e2003-12-23 08:09:43 +00002788
2789 /* first we find the maximal node */
paula8f03df2005-04-10 15:58:10 +00002790 for (ALL_LIST_ELEMENTS_RO (area->topology, node, arc))
Josh Bailey3f045a02012-03-24 08:35:20 -07002791 {
2792 if (arc->from_node > max)
2793 max = arc->from_node;
2794 if (arc->to_node > max)
2795 max = arc->to_node;
2796 }
jardineb5d44e2003-12-23 08:09:43 +00002797
hassof390d2c2004-09-10 20:48:21 +00002798 for (i = 1; i < (max + 1); i++)
2799 {
2800 memcpy (lspid, area->topology_baseis, ISIS_SYS_ID_LEN);
2801 LSP_PSEUDO_ID (lspid) = 0x00;
2802 LSP_FRAGMENT (lspid) = 0x00;
2803 lspid[ISIS_SYS_ID_LEN - 1] = (i & 0xFF);
2804 lspid[ISIS_SYS_ID_LEN - 2] = ((i >> 8) & 0xFF);
jardineb5d44e2003-12-23 08:09:43 +00002805
Josh Bailey3f045a02012-03-24 08:35:20 -07002806 rem_lifetime = lsp_rem_lifetime (area, IS_LEVEL_1);
Christian Frankef1fc1db2015-11-10 18:43:31 +01002807 lsp = lsp_new (area, lspid, rem_lifetime, 1,
2808 IS_LEVEL_1 | area->overload_bit | area->attached_bit,
2809 0, 1);
hassof1082d12005-09-19 04:23:34 +00002810 if (!lsp)
2811 return;
Josh Bailey3f045a02012-03-24 08:35:20 -07002812 lsp->from_topology = 1;
jardineb5d44e2003-12-23 08:09:43 +00002813
hassof1082d12005-09-19 04:23:34 +00002814 /* Creating LSP data based on topology info. */
2815 build_topology_lsp_data (lsp, area, i);
2816 /* Checksum is also calculated here. */
2817 lsp_seqnum_update (lsp);
hasso9551eea2005-09-28 18:26:25 +00002818 /* Take care of inserting dynamic hostname into cache. */
2819 isis_dynhn_insert (lspid, lsp->tlv_data.hostname, IS_LEVEL_1);
hassof1082d12005-09-19 04:23:34 +00002820
Josh Bailey3f045a02012-03-24 08:35:20 -07002821 refresh_time = lsp_refresh_time (lsp, rem_lifetime);
hassof1082d12005-09-19 04:23:34 +00002822 THREAD_TIMER_ON (master, lsp->t_lsp_top_ref, top_lsp_refresh, lsp,
Josh Bailey3f045a02012-03-24 08:35:20 -07002823 refresh_time);
2824 lsp_set_all_srmflags (lsp);
hassof390d2c2004-09-10 20:48:21 +00002825 lsp_insert (lsp, area->lspdb[0]);
hassof390d2c2004-09-10 20:48:21 +00002826 }
jardineb5d44e2003-12-23 08:09:43 +00002827}
2828
2829void
2830remove_topology_lsps (struct isis_area *area)
2831{
2832 struct isis_lsp *lsp;
2833 dnode_t *dnode, *dnode_next;
2834
2835 dnode = dict_first (area->lspdb[0]);
hassof390d2c2004-09-10 20:48:21 +00002836 while (dnode != NULL)
2837 {
2838 dnode_next = dict_next (area->lspdb[0], dnode);
2839 lsp = dnode_get (dnode);
2840 if (lsp->from_topology)
2841 {
2842 THREAD_TIMER_OFF (lsp->t_lsp_top_ref);
2843 lsp_destroy (lsp);
2844 dict_delete (area->lspdb[0], dnode);
2845 }
2846 dnode = dnode_next;
jardineb5d44e2003-12-23 08:09:43 +00002847 }
jardineb5d44e2003-12-23 08:09:43 +00002848}
2849
2850void
hassof390d2c2004-09-10 20:48:21 +00002851build_topology_lsp_data (struct isis_lsp *lsp, struct isis_area *area,
jardineb5d44e2003-12-23 08:09:43 +00002852 int lsp_top_num)
2853{
hasso3fdb2dd2005-09-28 18:45:54 +00002854 struct listnode *node;
jardineb5d44e2003-12-23 08:09:43 +00002855 struct arc *arc;
jardineb5d44e2003-12-23 08:09:43 +00002856 struct is_neigh *is_neigh;
hasso9551eea2005-09-28 18:26:25 +00002857 struct te_is_neigh *te_is_neigh;
jardineb5d44e2003-12-23 08:09:43 +00002858 char buff[200];
hassof1082d12005-09-19 04:23:34 +00002859 struct tlvs tlv_data;
2860 struct isis_lsp *lsp0 = lsp;
jardineb5d44e2003-12-23 08:09:43 +00002861
hassof1082d12005-09-19 04:23:34 +00002862 /* Add area addresses. FIXME: Is it needed at all? */
2863 if (lsp->tlv_data.area_addrs == NULL)
2864 lsp->tlv_data.area_addrs = list_new ();
2865 list_add_list (lsp->tlv_data.area_addrs, area->area_addrs);
jardineb5d44e2003-12-23 08:09:43 +00002866
hassof1082d12005-09-19 04:23:34 +00002867 if (lsp->tlv_data.nlpids == NULL)
2868 lsp->tlv_data.nlpids = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct nlpids));
2869 lsp->tlv_data.nlpids->count = 1;
2870 lsp->tlv_data.nlpids->nlpids[0] = NLPID_IP;
jardineb5d44e2003-12-23 08:09:43 +00002871
hassof1082d12005-09-19 04:23:34 +00002872 if (area->dynhostname)
2873 {
2874 lsp->tlv_data.hostname = XMALLOC (MTYPE_ISIS_TLV,
2875 sizeof (struct hostname));
2876 memset (buff, 0x00, 200);
2877 sprintf (buff, "%s%d", area->topology_basedynh ? area->topology_basedynh :
2878 "feedme", lsp_top_num);
2879 memcpy (lsp->tlv_data.hostname->name, buff, strlen (buff));
2880 lsp->tlv_data.hostname->namelen = strlen (buff);
2881 }
2882
2883 if (lsp->tlv_data.nlpids)
2884 tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu);
2885 if (lsp->tlv_data.hostname)
2886 tlv_add_dynamic_hostname (lsp->tlv_data.hostname, lsp->pdu);
2887 if (lsp->tlv_data.area_addrs && listcount (lsp->tlv_data.area_addrs) > 0)
2888 tlv_add_area_addrs (lsp->tlv_data.area_addrs, lsp->pdu);
2889
2890 memset (&tlv_data, 0, sizeof (struct tlvs));
2891 if (tlv_data.is_neighs == NULL)
hasso9551eea2005-09-28 18:26:25 +00002892 {
2893 tlv_data.is_neighs = list_new ();
2894 tlv_data.is_neighs->del = free_tlv;
2895 }
hassof1082d12005-09-19 04:23:34 +00002896
2897 /* Add reachability for this IS for simulated 1. */
hassof390d2c2004-09-10 20:48:21 +00002898 if (lsp_top_num == 1)
2899 {
hasso3fdb2dd2005-09-28 18:45:54 +00002900 is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
hassof1082d12005-09-19 04:23:34 +00002901
hassof390d2c2004-09-10 20:48:21 +00002902 memcpy (&is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN);
jardineb5d44e2003-12-23 08:09:43 +00002903 LSP_PSEUDO_ID (is_neigh->neigh_id) = 0x00;
hassof1082d12005-09-19 04:23:34 +00002904 /* Metric MUST NOT be 0, unless it's not alias TLV. */
2905 is_neigh->metrics.metric_default = 0x01;
jardineb5d44e2003-12-23 08:09:43 +00002906 is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED;
2907 is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED;
2908 is_neigh->metrics.metric_error = METRICS_UNSUPPORTED;
hassof1082d12005-09-19 04:23:34 +00002909 listnode_add (tlv_data.is_neighs, is_neigh);
jardineb5d44e2003-12-23 08:09:43 +00002910 }
hassof390d2c2004-09-10 20:48:21 +00002911
hassof1082d12005-09-19 04:23:34 +00002912 /* Add IS reachabilities. */
hasso3fdb2dd2005-09-28 18:45:54 +00002913 for (ALL_LIST_ELEMENTS_RO (area->topology, node, arc))
hassof390d2c2004-09-10 20:48:21 +00002914 {
hassof1082d12005-09-19 04:23:34 +00002915 int to_lsp = 0;
2916
2917 if ((lsp_top_num != arc->from_node) && (lsp_top_num != arc->to_node))
2918 continue;
2919
2920 if (lsp_top_num == arc->from_node)
2921 to_lsp = arc->to_node;
2922 else
2923 to_lsp = arc->from_node;
2924
hasso9551eea2005-09-28 18:26:25 +00002925 if (area->oldmetric)
2926 {
2927 is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
hassof1082d12005-09-19 04:23:34 +00002928
hasso9551eea2005-09-28 18:26:25 +00002929 memcpy (&is_neigh->neigh_id, area->topology_baseis, ISIS_SYS_ID_LEN);
2930 is_neigh->neigh_id[ISIS_SYS_ID_LEN - 1] = (to_lsp & 0xFF);
2931 is_neigh->neigh_id[ISIS_SYS_ID_LEN - 2] = ((to_lsp >> 8) & 0xFF);
2932 is_neigh->metrics.metric_default = arc->distance;
2933 is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED;
2934 is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED;
2935 is_neigh->metrics.metric_error = METRICS_UNSUPPORTED;
2936 listnode_add (tlv_data.is_neighs, is_neigh);
2937 }
2938
2939 if (area->newmetric)
2940 {
hasso9551eea2005-09-28 18:26:25 +00002941 if (tlv_data.te_is_neighs == NULL)
2942 {
2943 tlv_data.te_is_neighs = list_new ();
2944 tlv_data.te_is_neighs->del = free_tlv;
2945 }
2946 te_is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct te_is_neigh));
2947 memcpy (&te_is_neigh->neigh_id, area->topology_baseis,
2948 ISIS_SYS_ID_LEN);
2949 te_is_neigh->neigh_id[ISIS_SYS_ID_LEN - 1] = (to_lsp & 0xFF);
2950 te_is_neigh->neigh_id[ISIS_SYS_ID_LEN - 2] = ((to_lsp >> 8) & 0xFF);
Josh Bailey3f045a02012-03-24 08:35:20 -07002951 SET_TE_METRIC(te_is_neigh, arc->distance);
hasso9551eea2005-09-28 18:26:25 +00002952 listnode_add (tlv_data.te_is_neighs, te_is_neigh);
2953 }
hassof390d2c2004-09-10 20:48:21 +00002954 }
hassof1082d12005-09-19 04:23:34 +00002955
2956 while (tlv_data.is_neighs && listcount (tlv_data.is_neighs))
2957 {
2958 if (lsp->tlv_data.is_neighs == NULL)
2959 lsp->tlv_data.is_neighs = list_new ();
hasso9551eea2005-09-28 18:26:25 +00002960 lsp_tlv_fit (lsp, &tlv_data.is_neighs, &lsp->tlv_data.is_neighs,
hassof1082d12005-09-19 04:23:34 +00002961 IS_NEIGHBOURS_LEN, area->lsp_frag_threshold,
2962 tlv_add_is_neighs);
2963 if (tlv_data.is_neighs && listcount (tlv_data.is_neighs))
2964 lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
2965 lsp0, area, IS_LEVEL_1);
2966 }
2967
hasso9551eea2005-09-28 18:26:25 +00002968 while (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs))
2969 {
2970 if (lsp->tlv_data.te_is_neighs == NULL)
2971 lsp->tlv_data.te_is_neighs = list_new ();
2972 lsp_tlv_fit (lsp, &tlv_data.te_is_neighs, &lsp->tlv_data.te_is_neighs,
2973 IS_NEIGHBOURS_LEN, area->lsp_frag_threshold,
2974 tlv_add_te_is_neighs);
2975 if (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs))
2976 lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
2977 lsp0, area, IS_LEVEL_1);
2978 }
2979
hassof1082d12005-09-19 04:23:34 +00002980 free_tlvs (&tlv_data);
2981 return;
jardineb5d44e2003-12-23 08:09:43 +00002982}
2983#endif /* TOPOLOGY_GENERATE */