]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_lsp.c
isisd: Don't use structs to encode/decode PDU header
[mirror_frr.git] / isisd / isis_lsp.c
1 /*
2 * IS-IS Rout(e)ing protocol - isis_lsp.c
3 * LSP processing
4 *
5 * Copyright (C) 2001,2002 Sampo Saaristo
6 * Tampere University of Technology
7 * Institute of Communications Engineering
8 * Copyright (C) 2013-2015 Christian Franke <chris@opensourcerouting.org>
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the Free
12 * 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; see the file COPYING; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25 #include <zebra.h>
26
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"
37 #include "checksum.h"
38 #include "md5.h"
39 #include "table.h"
40
41 #include "isisd/dict.h"
42 #include "isisd/isis_constants.h"
43 #include "isisd/isis_common.h"
44 #include "isisd/isis_flags.h"
45 #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"
52 #include "isisd/isis_csm.h"
53 #include "isisd/isis_adjacency.h"
54 #include "isisd/isis_spf.h"
55 #include "isisd/isis_te.h"
56 #include "isisd/isis_mt.h"
57
58 /* staticly assigned vars for printing purposes */
59 char lsp_bits_string[200]; /* FIXME: enough ? */
60
61 static int lsp_l1_refresh(struct thread *thread);
62 static int lsp_l2_refresh(struct thread *thread);
63 static int lsp_l1_refresh_pseudo(struct thread *thread);
64 static int lsp_l2_refresh_pseudo(struct thread *thread);
65
66 int lsp_id_cmp(u_char *id1, u_char *id2)
67 {
68 return memcmp(id1, id2, ISIS_SYS_ID_LEN + 2);
69 }
70
71 dict_t *lsp_db_init(void)
72 {
73 dict_t *dict;
74
75 dict = dict_create(DICTCOUNT_T_MAX, (dict_comp_t)lsp_id_cmp);
76
77 return dict;
78 }
79
80 struct isis_lsp *lsp_search(u_char *id, dict_t *lspdb)
81 {
82 dnode_t *node;
83
84 #ifdef EXTREME_DEBUG
85 dnode_t *dn;
86
87 zlog_debug("searching db");
88 for (dn = dict_first(lspdb); dn; dn = dict_next(lspdb, dn)) {
89 zlog_debug("%s\t%pX",
90 rawlspid_print((u_char *)dnode_getkey(dn)),
91 dnode_get(dn));
92 }
93 #endif /* EXTREME DEBUG */
94
95 node = dict_lookup(lspdb, id);
96
97 if (node)
98 return (struct isis_lsp *)dnode_get(node);
99
100 return NULL;
101 }
102
103 static void lsp_clear_data(struct isis_lsp *lsp)
104 {
105 if (!lsp)
106 return;
107
108 if (lsp->tlv_data.hostname)
109 isis_dynhn_remove(lsp->lsp_header->lsp_id);
110
111 if (lsp->own_lsp) {
112 if (lsp->tlv_data.nlpids)
113 XFREE(MTYPE_ISIS_TLV, lsp->tlv_data.nlpids);
114 if (lsp->tlv_data.hostname)
115 XFREE(MTYPE_ISIS_TLV, lsp->tlv_data.hostname);
116 if (lsp->tlv_data.router_id)
117 XFREE(MTYPE_ISIS_TLV, lsp->tlv_data.router_id);
118 }
119
120 free_tlvs(&lsp->tlv_data);
121 }
122
123 static void lsp_destroy(struct isis_lsp *lsp)
124 {
125 struct listnode *cnode, *lnode, *lnnode;
126 struct isis_lsp *lsp_in_list;
127 struct isis_circuit *circuit;
128
129 if (!lsp)
130 return;
131
132 if (lsp->area->circuit_list) {
133 for (ALL_LIST_ELEMENTS_RO(lsp->area->circuit_list, cnode,
134 circuit)) {
135 if (circuit->lsp_queue == NULL)
136 continue;
137 for (ALL_LIST_ELEMENTS(circuit->lsp_queue, lnode,
138 lnnode, lsp_in_list))
139 if (lsp_in_list == lsp)
140 list_delete_node(circuit->lsp_queue,
141 lnode);
142 }
143 }
144 ISIS_FLAGS_CLEAR_ALL(lsp->SSNflags);
145 ISIS_FLAGS_CLEAR_ALL(lsp->SRMflags);
146
147 lsp_clear_data(lsp);
148
149 if (LSP_FRAGMENT(lsp->lsp_header->lsp_id) == 0 && lsp->lspu.frags) {
150 list_delete(lsp->lspu.frags);
151 lsp->lspu.frags = NULL;
152 }
153
154 isis_spf_schedule(lsp->area, lsp->level);
155
156 if (lsp->pdu)
157 stream_free(lsp->pdu);
158 XFREE(MTYPE_ISIS_LSP, lsp);
159 }
160
161 void lsp_db_destroy(dict_t *lspdb)
162 {
163 dnode_t *dnode, *next;
164 struct isis_lsp *lsp;
165
166 dnode = dict_first(lspdb);
167 while (dnode) {
168 next = dict_next(lspdb, dnode);
169 lsp = dnode_get(dnode);
170 lsp_destroy(lsp);
171 dict_delete_free(lspdb, dnode);
172 dnode = next;
173 }
174
175 dict_free(lspdb);
176
177 return;
178 }
179
180 /*
181 * Remove all the frags belonging to the given lsp
182 */
183 static void lsp_remove_frags(struct list *frags, dict_t *lspdb)
184 {
185 dnode_t *dnode;
186 struct listnode *lnode, *lnnode;
187 struct isis_lsp *lsp;
188
189 for (ALL_LIST_ELEMENTS(frags, lnode, lnnode, lsp)) {
190 dnode = dict_lookup(lspdb, lsp->lsp_header->lsp_id);
191 lsp_destroy(lsp);
192 dnode_destroy(dict_delete(lspdb, dnode));
193 }
194
195 list_delete_all_node(frags);
196
197 return;
198 }
199
200 void lsp_search_and_destroy(u_char *id, dict_t *lspdb)
201 {
202 dnode_t *node;
203 struct isis_lsp *lsp;
204
205 node = dict_lookup(lspdb, id);
206 if (node) {
207 node = dict_delete(lspdb, node);
208 lsp = dnode_get(node);
209 /*
210 * If this is a zero lsp, remove all the frags now
211 */
212 if (LSP_FRAGMENT(lsp->lsp_header->lsp_id) == 0) {
213 if (lsp->lspu.frags)
214 lsp_remove_frags(lsp->lspu.frags, lspdb);
215 } else {
216 /*
217 * else just remove this frag, from the zero lsps' frag
218 * list
219 */
220 if (lsp->lspu.zero_lsp
221 && lsp->lspu.zero_lsp->lspu.frags)
222 listnode_delete(lsp->lspu.zero_lsp->lspu.frags,
223 lsp);
224 }
225 lsp_destroy(lsp);
226 dnode_destroy(node);
227 }
228 }
229
230 /*
231 * Compares a LSP to given values
232 * Params are given in net order
233 */
234 int lsp_compare(char *areatag, struct isis_lsp *lsp, u_int32_t seq_num,
235 u_int16_t checksum, u_int16_t rem_lifetime)
236 {
237 /* no point in double ntohl on seqnum */
238 if (lsp->lsp_header->seq_num == seq_num
239 && lsp->lsp_header->checksum == checksum &&
240 /*comparing with 0, no need to do ntohl */
241 ((lsp->lsp_header->rem_lifetime == 0 && rem_lifetime == 0)
242 || (lsp->lsp_header->rem_lifetime != 0 && rem_lifetime != 0))) {
243 if (isis->debugs & DEBUG_SNP_PACKETS) {
244 zlog_debug(
245 "ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x,"
246 " lifetime %us",
247 areatag,
248 rawlspid_print(lsp->lsp_header->lsp_id),
249 ntohl(lsp->lsp_header->seq_num),
250 ntohs(lsp->lsp_header->checksum),
251 ntohs(lsp->lsp_header->rem_lifetime));
252 zlog_debug(
253 "ISIS-Snp (%s): is equal to ours seq 0x%08x,"
254 " cksum 0x%04x, lifetime %us",
255 areatag, ntohl(seq_num), ntohs(checksum),
256 ntohs(rem_lifetime));
257 }
258 return LSP_EQUAL;
259 }
260
261 /*
262 * LSPs with identical checksums should only be treated as newer if:
263 * a) The current LSP has a remaining lifetime != 0 and the other LSP
264 * has a
265 * remaining lifetime == 0. In this case, we should participate in
266 * the purge
267 * and should not treat the current LSP with remaining lifetime == 0
268 * as older.
269 * b) The LSP has an incorrect checksum. In this case, we need to react
270 * as given
271 * in 7.3.16.2.
272 */
273 if (ntohl(seq_num) > ntohl(lsp->lsp_header->seq_num)
274 || (ntohl(seq_num) == ntohl(lsp->lsp_header->seq_num)
275 && ((lsp->lsp_header->rem_lifetime != 0 && rem_lifetime == 0)
276 || lsp->lsp_header->checksum != checksum))) {
277 if (isis->debugs & DEBUG_SNP_PACKETS) {
278 zlog_debug(
279 "ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x,"
280 " lifetime %us",
281 areatag,
282 rawlspid_print(lsp->lsp_header->lsp_id),
283 ntohl(seq_num), ntohs(checksum),
284 ntohs(rem_lifetime));
285 zlog_debug(
286 "ISIS-Snp (%s): is newer than ours seq 0x%08x, "
287 "cksum 0x%04x, lifetime %us",
288 areatag, ntohl(lsp->lsp_header->seq_num),
289 ntohs(lsp->lsp_header->checksum),
290 ntohs(lsp->lsp_header->rem_lifetime));
291 }
292 return LSP_NEWER;
293 }
294 if (isis->debugs & DEBUG_SNP_PACKETS) {
295 zlog_debug(
296 "ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x, lifetime %us",
297 areatag, rawlspid_print(lsp->lsp_header->lsp_id),
298 ntohl(seq_num), ntohs(checksum), ntohs(rem_lifetime));
299 zlog_debug(
300 "ISIS-Snp (%s): is older than ours seq 0x%08x,"
301 " cksum 0x%04x, lifetime %us",
302 areatag, ntohl(lsp->lsp_header->seq_num),
303 ntohs(lsp->lsp_header->checksum),
304 ntohs(lsp->lsp_header->rem_lifetime));
305 }
306
307 return LSP_OLDER;
308 }
309
310 static void lsp_auth_add(struct isis_lsp *lsp)
311 {
312 struct isis_passwd *passwd;
313 unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
314
315 /*
316 * Add the authentication info if its present
317 */
318 (lsp->level == IS_LEVEL_1) ? (passwd = &lsp->area->area_passwd)
319 : (passwd = &lsp->area->domain_passwd);
320 switch (passwd->type) {
321 /* Cleartext */
322 case ISIS_PASSWD_TYPE_CLEARTXT:
323 memcpy(&lsp->tlv_data.auth_info, passwd,
324 sizeof(struct isis_passwd));
325 tlv_add_authinfo(passwd->type, passwd->len, passwd->passwd,
326 lsp->pdu);
327 break;
328
329 /* HMAC MD5 */
330 case ISIS_PASSWD_TYPE_HMAC_MD5:
331 /* Remember where TLV is written so we can later
332 * overwrite the MD5 hash */
333 lsp->auth_tlv_offset = stream_get_endp(lsp->pdu);
334 memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
335 lsp->tlv_data.auth_info.type = ISIS_PASSWD_TYPE_HMAC_MD5;
336 lsp->tlv_data.auth_info.len = ISIS_AUTH_MD5_SIZE;
337 memcpy(&lsp->tlv_data.auth_info.passwd, hmac_md5_hash,
338 ISIS_AUTH_MD5_SIZE);
339 tlv_add_authinfo(passwd->type, ISIS_AUTH_MD5_SIZE,
340 hmac_md5_hash, lsp->pdu);
341 break;
342
343 default:
344 break;
345 }
346 }
347
348 static void lsp_auth_update(struct isis_lsp *lsp)
349 {
350 struct isis_passwd *passwd;
351 unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
352 uint16_t checksum, rem_lifetime;
353
354 /* For HMAC MD5 we need to recompute the md5 hash and store it */
355 (lsp->level == IS_LEVEL_1) ? (passwd = &lsp->area->area_passwd)
356 : (passwd = &lsp->area->domain_passwd);
357 if (passwd->type != ISIS_PASSWD_TYPE_HMAC_MD5)
358 return;
359
360 /*
361 * In transient conditions (when net is configured where authentication
362 * config and lsp regenerate schedule is not yet run), there could be
363 * an own_lsp with auth_tlv_offset set to 0. In such a case, simply
364 * return, when lsp_regenerate is run, lsp will have auth tlv.
365 */
366 if (lsp->auth_tlv_offset == 0)
367 return;
368
369 /*
370 * RFC 5304 set auth value, checksum and remaining lifetime to zero
371 * before computation and reset to old values after computation.
372 */
373 checksum = lsp->lsp_header->checksum;
374 rem_lifetime = lsp->lsp_header->rem_lifetime;
375 lsp->lsp_header->checksum = 0;
376 lsp->lsp_header->rem_lifetime = 0;
377 /* Set the authentication value as well to zero */
378 memset(STREAM_DATA(lsp->pdu) + lsp->auth_tlv_offset + 3, 0,
379 ISIS_AUTH_MD5_SIZE);
380 /* Compute autentication value */
381 hmac_md5(STREAM_DATA(lsp->pdu), stream_get_endp(lsp->pdu),
382 (unsigned char *)&passwd->passwd, passwd->len,
383 (unsigned char *)&hmac_md5_hash);
384 /* Copy the hash into the stream */
385 memcpy(STREAM_DATA(lsp->pdu) + lsp->auth_tlv_offset + 3, hmac_md5_hash,
386 ISIS_AUTH_MD5_SIZE);
387 memcpy(&lsp->tlv_data.auth_info.passwd, hmac_md5_hash,
388 ISIS_AUTH_MD5_SIZE);
389 /* Copy back the checksum and remaining lifetime */
390 lsp->lsp_header->checksum = checksum;
391 lsp->lsp_header->rem_lifetime = rem_lifetime;
392 }
393
394 void lsp_inc_seqnum(struct isis_lsp *lsp, u_int32_t seq_num)
395 {
396 u_int32_t newseq;
397
398 if (seq_num == 0 || ntohl(lsp->lsp_header->seq_num) > seq_num)
399 newseq = ntohl(lsp->lsp_header->seq_num) + 1;
400 else
401 newseq = seq_num + 1;
402
403 lsp->lsp_header->seq_num = htonl(newseq);
404
405 /* Recompute authentication and checksum information */
406 lsp_auth_update(lsp);
407 /* ISO 10589 - 7.3.11 Generation of the checksum
408 * The checksum shall be computed over all fields in the LSP which
409 * appear
410 * after the Remaining Lifetime field. This field (and those appearing
411 * before it) are excluded so that the LSP may be aged by systems
412 * without
413 * requiring recomputation.
414 */
415 fletcher_checksum(STREAM_DATA(lsp->pdu) + 12,
416 ntohs(lsp->lsp_header->pdu_len) - 12, 12);
417
418 isis_spf_schedule(lsp->area, lsp->level);
419
420 return;
421 }
422
423 /*
424 * Genetates checksum for LSP and its frags
425 */
426 static void lsp_seqnum_update(struct isis_lsp *lsp0)
427 {
428 struct isis_lsp *lsp;
429 struct listnode *node;
430
431 lsp_inc_seqnum(lsp0, 0);
432
433 if (!lsp0->lspu.frags)
434 return;
435
436 for (ALL_LIST_ELEMENTS_RO(lsp0->lspu.frags, node, lsp))
437 lsp_inc_seqnum(lsp, 0);
438
439 return;
440 }
441
442 static u_int8_t lsp_bits_generate(int level, int overload_bit, int attached_bit)
443 {
444 u_int8_t lsp_bits = 0;
445 if (level == IS_LEVEL_1)
446 lsp_bits = IS_LEVEL_1;
447 else
448 lsp_bits = IS_LEVEL_1_AND_2;
449 if (overload_bit)
450 lsp_bits |= overload_bit;
451 if (attached_bit)
452 lsp_bits |= attached_bit;
453 return lsp_bits;
454 }
455
456 static void lsp_update_data(struct isis_lsp *lsp, struct stream *stream,
457 struct isis_area *area, int level)
458 {
459 uint32_t expected = 0, found;
460 int retval;
461
462 /* free the old lsp data */
463 lsp_clear_data(lsp);
464
465 /* copying only the relevant part of our stream */
466 if (lsp->pdu != NULL)
467 stream_free(lsp->pdu);
468 lsp->pdu = stream_dup(stream);
469
470 /* setting pointers to the correct place */
471 lsp->lsp_header = (struct isis_link_state_hdr *)(STREAM_DATA(lsp->pdu)
472 + ISIS_FIXED_HDR_LEN);
473 lsp->area = area;
474 lsp->level = level;
475 lsp->age_out = ZERO_AGE_LIFETIME;
476 lsp->installed = time(NULL);
477 /*
478 * Get LSP data i.e. TLVs
479 */
480 expected |= TLVFLAG_AUTH_INFO;
481 expected |= TLVFLAG_AREA_ADDRS;
482 expected |= TLVFLAG_IS_NEIGHS;
483 expected |= TLVFLAG_NLPID;
484 if (area->dynhostname)
485 expected |= TLVFLAG_DYN_HOSTNAME;
486 if (area->newmetric) {
487 expected |= TLVFLAG_TE_IS_NEIGHS;
488 expected |= TLVFLAG_TE_IPV4_REACHABILITY;
489 expected |= TLVFLAG_TE_ROUTER_ID;
490 }
491 expected |= TLVFLAG_MT_ROUTER_INFORMATION;
492 expected |= TLVFLAG_IPV4_ADDR;
493 expected |= TLVFLAG_IPV4_INT_REACHABILITY;
494 expected |= TLVFLAG_IPV4_EXT_REACHABILITY;
495 expected |= TLVFLAG_IPV6_ADDR;
496 expected |= TLVFLAG_IPV6_REACHABILITY;
497
498 retval = parse_tlvs(area->area_tag,
499 STREAM_DATA(lsp->pdu) + ISIS_FIXED_HDR_LEN
500 + ISIS_LSP_HDR_LEN,
501 ntohs(lsp->lsp_header->pdu_len) - ISIS_FIXED_HDR_LEN
502 - ISIS_LSP_HDR_LEN,
503 &expected, &found, &lsp->tlv_data, NULL);
504 if (retval != ISIS_OK) {
505 zlog_warn("Could not parse LSP");
506 return;
507 }
508
509 if ((found & TLVFLAG_DYN_HOSTNAME) && (area->dynhostname)) {
510 isis_dynhn_insert(lsp->lsp_header->lsp_id,
511 lsp->tlv_data.hostname,
512 (lsp->lsp_header->lsp_bits & LSPBIT_IST)
513 == IS_LEVEL_1_AND_2
514 ? IS_LEVEL_2
515 : IS_LEVEL_1);
516 }
517
518 return;
519 }
520
521 void lsp_update(struct isis_lsp *lsp, struct stream *stream,
522 struct isis_area *area, int level)
523 {
524 dnode_t *dnode = NULL;
525
526 /* Remove old LSP from database. This is required since the
527 * lsp_update_data will free the lsp->pdu (which has the key, lsp_id)
528 * and will update it with the new data in the stream. */
529 dnode = dict_lookup(area->lspdb[level - 1], lsp->lsp_header->lsp_id);
530 if (dnode)
531 dnode_destroy(dict_delete(area->lspdb[level - 1], dnode));
532
533 if (lsp->own_lsp) {
534 zlog_err(
535 "ISIS-Upd (%s): BUG updating LSP %s still marked as own LSP",
536 area->area_tag,
537 rawlspid_print(lsp->lsp_header->lsp_id));
538 lsp_clear_data(lsp);
539 lsp->own_lsp = 0;
540 }
541
542 /* rebuild the lsp data */
543 lsp_update_data(lsp, stream, area, level);
544
545 /* insert the lsp back into the database */
546 lsp_insert(lsp, area->lspdb[level - 1]);
547 }
548
549 /* creation of LSP directly from what we received */
550 struct isis_lsp *lsp_new_from_stream_ptr(struct stream *stream,
551 u_int16_t pdu_len,
552 struct isis_lsp *lsp0,
553 struct isis_area *area, int level)
554 {
555 struct isis_lsp *lsp;
556
557 lsp = XCALLOC(MTYPE_ISIS_LSP, sizeof(struct isis_lsp));
558 lsp_update_data(lsp, stream, area, level);
559
560 if (lsp0 == NULL) {
561 /*
562 * zero lsp -> create the list for fragments
563 */
564 lsp->lspu.frags = list_new();
565 } else {
566 /*
567 * a fragment -> set the backpointer and add this to zero lsps
568 * frag list
569 */
570 lsp->lspu.zero_lsp = lsp0;
571 listnode_add(lsp0->lspu.frags, lsp);
572 }
573
574 return lsp;
575 }
576
577 struct isis_lsp *lsp_new(struct isis_area *area, u_char *lsp_id,
578 u_int16_t rem_lifetime, u_int32_t seq_num,
579 u_int8_t lsp_bits, u_int16_t checksum, int level)
580 {
581 struct isis_lsp *lsp;
582 uint8_t pdu_type =
583 (level == IS_LEVEL_1) ? L1_LINK_STATE : L2_LINK_STATE;
584
585 lsp = XCALLOC(MTYPE_ISIS_LSP, sizeof(struct isis_lsp));
586 lsp->area = area;
587
588 lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu);
589 if (LSP_FRAGMENT(lsp_id) == 0)
590 lsp->lspu.frags = list_new();
591
592 fill_fixed_hdr(pdu_type, lsp->pdu);
593
594 /* now for the LSP HEADER */
595 /* Minimal LSP PDU size */
596 lsp->lsp_header = (struct isis_link_state_hdr *)(STREAM_DATA(lsp->pdu)
597 + ISIS_FIXED_HDR_LEN);
598 lsp->lsp_header->pdu_len = htons(ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
599 memcpy(lsp->lsp_header->lsp_id, lsp_id, ISIS_SYS_ID_LEN + 2);
600 lsp->lsp_header->checksum = checksum; /* Provided in network order */
601 lsp->lsp_header->seq_num = htonl(seq_num);
602 lsp->lsp_header->rem_lifetime = htons(rem_lifetime);
603 lsp->lsp_header->lsp_bits = lsp_bits;
604 lsp->level = level;
605 lsp->age_out = ZERO_AGE_LIFETIME;
606
607 stream_forward_endp(lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
608
609 if (isis->debugs & DEBUG_EVENTS)
610 zlog_debug("New LSP with ID %s-%02x-%02x len %d seqnum %08x",
611 sysid_print(lsp_id),
612 LSP_PSEUDO_ID(lsp->lsp_header->lsp_id),
613 LSP_FRAGMENT(lsp->lsp_header->lsp_id),
614 ntohl(lsp->lsp_header->pdu_len),
615 ntohl(lsp->lsp_header->seq_num));
616
617 return lsp;
618 }
619
620 void lsp_insert(struct isis_lsp *lsp, dict_t *lspdb)
621 {
622 dict_alloc_insert(lspdb, lsp->lsp_header->lsp_id, lsp);
623 if (lsp->lsp_header->seq_num != 0) {
624 isis_spf_schedule(lsp->area, lsp->level);
625 }
626 }
627
628 /*
629 * Build a list of LSPs with non-zero ht bounded by start and stop ids
630 */
631 void lsp_build_list_nonzero_ht(u_char *start_id, u_char *stop_id,
632 struct list *list, dict_t *lspdb)
633 {
634 dnode_t *first, *last, *curr;
635
636 first = dict_lower_bound(lspdb, start_id);
637 if (!first)
638 return;
639
640 last = dict_upper_bound(lspdb, stop_id);
641
642 curr = first;
643
644 if (((struct isis_lsp *)(curr->dict_data))->lsp_header->rem_lifetime)
645 listnode_add(list, first->dict_data);
646
647 while (curr) {
648 curr = dict_next(lspdb, curr);
649 if (curr
650 && ((struct isis_lsp *)(curr->dict_data))
651 ->lsp_header->rem_lifetime)
652 listnode_add(list, curr->dict_data);
653 if (curr == last)
654 break;
655 }
656
657 return;
658 }
659
660 /*
661 * Build a list of num_lsps LSPs bounded by start_id and stop_id.
662 */
663 void lsp_build_list(u_char *start_id, u_char *stop_id, u_char num_lsps,
664 struct list *list, dict_t *lspdb)
665 {
666 u_char count;
667 dnode_t *first, *last, *curr;
668
669 first = dict_lower_bound(lspdb, start_id);
670 if (!first)
671 return;
672
673 last = dict_upper_bound(lspdb, stop_id);
674
675 curr = first;
676
677 listnode_add(list, first->dict_data);
678 count = 1;
679
680 while (curr) {
681 curr = dict_next(lspdb, curr);
682 if (curr) {
683 listnode_add(list, curr->dict_data);
684 count++;
685 }
686 if (count == num_lsps || curr == last)
687 break;
688 }
689
690 return;
691 }
692
693 /*
694 * Build a list of LSPs with SSN flag set for the given circuit
695 */
696 void lsp_build_list_ssn(struct isis_circuit *circuit, u_char num_lsps,
697 struct list *list, dict_t *lspdb)
698 {
699 dnode_t *dnode, *next;
700 struct isis_lsp *lsp;
701 u_char count = 0;
702
703 dnode = dict_first(lspdb);
704 while (dnode != NULL) {
705 next = dict_next(lspdb, dnode);
706 lsp = dnode_get(dnode);
707 if (ISIS_CHECK_FLAG(lsp->SSNflags, circuit)) {
708 listnode_add(list, lsp);
709 ++count;
710 }
711 if (count == num_lsps)
712 break;
713 dnode = next;
714 }
715
716 return;
717 }
718
719 static void lsp_set_time(struct isis_lsp *lsp)
720 {
721 assert(lsp);
722
723 if (lsp->lsp_header->rem_lifetime == 0) {
724 if (lsp->age_out > 0)
725 lsp->age_out--;
726 return;
727 }
728
729 lsp->lsp_header->rem_lifetime =
730 htons(ntohs(lsp->lsp_header->rem_lifetime) - 1);
731 }
732
733 static void lspid_print(u_char *lsp_id, u_char *trg, char dynhost, char frag)
734 {
735 struct isis_dynhn *dyn = NULL;
736 u_char id[SYSID_STRLEN];
737
738 if (dynhost)
739 dyn = dynhn_find_by_id(lsp_id);
740 else
741 dyn = NULL;
742
743 if (dyn)
744 sprintf((char *)id, "%.14s", dyn->name.name);
745 else if (!memcmp(isis->sysid, lsp_id, ISIS_SYS_ID_LEN) && dynhost)
746 sprintf((char *)id, "%.14s", unix_hostname());
747 else
748 memcpy(id, sysid_print(lsp_id), 15);
749 if (frag)
750 sprintf((char *)trg, "%s.%02x-%02x", id, LSP_PSEUDO_ID(lsp_id),
751 LSP_FRAGMENT(lsp_id));
752 else
753 sprintf((char *)trg, "%s.%02x", id, LSP_PSEUDO_ID(lsp_id));
754 }
755
756 /* Convert the lsp attribute bits to attribute string */
757 const char *lsp_bits2string(u_char *lsp_bits)
758 {
759 char *pos = lsp_bits_string;
760
761 if (!*lsp_bits)
762 return " none";
763
764 /* we only focus on the default metric */
765 pos += sprintf(pos, "%d/",
766 ISIS_MASK_LSP_ATT_DEFAULT_BIT(*lsp_bits) ? 1 : 0);
767
768 pos += sprintf(pos, "%d/",
769 ISIS_MASK_LSP_PARTITION_BIT(*lsp_bits) ? 1 : 0);
770
771 pos += sprintf(pos, "%d", ISIS_MASK_LSP_OL_BIT(*lsp_bits) ? 1 : 0);
772
773 *(pos) = '\0';
774
775 return lsp_bits_string;
776 }
777
778 /* this function prints the lsp on show isis database */
779 void lsp_print(struct isis_lsp *lsp, struct vty *vty, char dynhost)
780 {
781 u_char LSPid[255];
782 char age_out[8];
783
784 lspid_print(lsp->lsp_header->lsp_id, LSPid, dynhost, 1);
785 vty_out(vty, "%-21s%c ", LSPid, lsp->own_lsp ? '*' : ' ');
786 vty_out(vty, "%5u ", ntohs(lsp->lsp_header->pdu_len));
787 vty_out(vty, "0x%08x ", ntohl(lsp->lsp_header->seq_num));
788 vty_out(vty, "0x%04x ", ntohs(lsp->lsp_header->checksum));
789 if (ntohs(lsp->lsp_header->rem_lifetime) == 0) {
790 snprintf(age_out, 8, "(%u)", lsp->age_out);
791 age_out[7] = '\0';
792 vty_out(vty, "%7s ", age_out);
793 } else
794 vty_out(vty, " %5u ", ntohs(lsp->lsp_header->rem_lifetime));
795 vty_out(vty, "%s\n", lsp_bits2string(&lsp->lsp_header->lsp_bits));
796 }
797
798 static void lsp_print_mt_reach(struct list *list, struct vty *vty, char dynhost,
799 uint16_t mtid)
800 {
801 struct listnode *node;
802 struct te_is_neigh *neigh;
803
804 for (ALL_LIST_ELEMENTS_RO(list, node, neigh)) {
805 u_char lspid[255];
806
807 lspid_print(neigh->neigh_id, lspid, dynhost, 0);
808 if (mtid == ISIS_MT_IPV4_UNICAST) {
809 vty_out(vty,
810 " Metric : %-8u IS-Extended : %s\n",
811 GET_TE_METRIC(neigh), lspid);
812 } else {
813 vty_out(vty,
814 " Metric : %-8u MT-Reach : %s %s\n",
815 GET_TE_METRIC(neigh), lspid,
816 isis_mtid2str(mtid));
817 }
818 if (IS_MPLS_TE(isisMplsTE))
819 mpls_te_print_detail(vty, neigh);
820 }
821 }
822
823 static void lsp_print_mt_ipv6_reach(struct list *list, struct vty *vty,
824 uint16_t mtid)
825 {
826 struct listnode *node;
827 struct ipv6_reachability *ipv6_reach;
828 struct in6_addr in6;
829 u_char buff[BUFSIZ];
830
831 for (ALL_LIST_ELEMENTS_RO(list, node, ipv6_reach)) {
832 memset(&in6, 0, sizeof(in6));
833 memcpy(in6.s6_addr, ipv6_reach->prefix,
834 PSIZE(ipv6_reach->prefix_len));
835 inet_ntop(AF_INET6, &in6, (char *)buff, BUFSIZ);
836 if (mtid == ISIS_MT_IPV4_UNICAST) {
837 if ((ipv6_reach->control_info & CTRL_INFO_DISTRIBUTION)
838 == DISTRIBUTION_INTERNAL)
839 vty_out(vty, " Metric : %-8" PRIu32
840 " IPv6-Internal : %s/%d\n",
841 ntohl(ipv6_reach->metric), buff,
842 ipv6_reach->prefix_len);
843 else
844 vty_out(vty, " Metric : %-8" PRIu32
845 " IPv6-External : %s/%d\n",
846 ntohl(ipv6_reach->metric), buff,
847 ipv6_reach->prefix_len);
848 } else {
849 if ((ipv6_reach->control_info & CTRL_INFO_DISTRIBUTION)
850 == DISTRIBUTION_INTERNAL)
851 vty_out(vty, " Metric : %-8" PRIu32
852 " IPv6-MT-Int : %s/%d %s\n",
853 ntohl(ipv6_reach->metric), buff,
854 ipv6_reach->prefix_len,
855 isis_mtid2str(mtid));
856 else
857 vty_out(vty, " Metric : %-8" PRIu32
858 " IPv6-MT-Ext : %s/%d %s\n",
859 ntohl(ipv6_reach->metric), buff,
860 ipv6_reach->prefix_len,
861 isis_mtid2str(mtid));
862 }
863 }
864 }
865
866 static void lsp_print_mt_ipv4_reach(struct list *list, struct vty *vty,
867 uint16_t mtid)
868 {
869 struct listnode *node;
870 struct te_ipv4_reachability *te_ipv4_reach;
871
872 for (ALL_LIST_ELEMENTS_RO(list, node, te_ipv4_reach)) {
873 if (mtid == ISIS_MT_IPV4_UNICAST) {
874 /* FIXME: There should be better way to output this
875 * stuff. */
876 vty_out(vty, " Metric : %-8" PRIu32
877 " IPv4-Extended : %s/%d\n",
878 ntohl(te_ipv4_reach->te_metric),
879 inet_ntoa(newprefix2inaddr(
880 &te_ipv4_reach->prefix_start,
881 te_ipv4_reach->control)),
882 te_ipv4_reach->control & 0x3F);
883 } else {
884 /* FIXME: There should be better way to output this
885 * stuff. */
886 vty_out(vty, " Metric : %-8" PRIu32
887 " IPv4-MT : %s/%d %s\n",
888 ntohl(te_ipv4_reach->te_metric),
889 inet_ntoa(newprefix2inaddr(
890 &te_ipv4_reach->prefix_start,
891 te_ipv4_reach->control)),
892 te_ipv4_reach->control & 0x3F,
893 isis_mtid2str(mtid));
894 }
895 }
896 }
897
898 void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty, char dynhost)
899 {
900 struct area_addr *area_addr;
901 int i;
902 struct listnode *lnode;
903 struct is_neigh *is_neigh;
904 struct ipv4_reachability *ipv4_reach;
905 struct in_addr *ipv4_addr;
906 struct mt_router_info *mt_router_info;
907 struct tlv_mt_ipv6_reachs *mt_ipv6_reachs;
908 struct tlv_mt_neighbors *mt_is_neigh;
909 struct tlv_mt_ipv4_reachs *mt_ipv4_reachs;
910 u_char LSPid[255];
911 u_char hostname[255];
912 u_char ipv4_reach_prefix[20];
913 u_char ipv4_reach_mask[20];
914 u_char ipv4_address[20];
915
916 lspid_print(lsp->lsp_header->lsp_id, LSPid, dynhost, 1);
917 lsp_print(lsp, vty, dynhost);
918
919 /* for all area address */
920 if (lsp->tlv_data.area_addrs)
921 for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.area_addrs, lnode,
922 area_addr)) {
923 vty_out(vty, " Area Address: %s\n",
924 isonet_print(area_addr->area_addr,
925 area_addr->addr_len));
926 }
927
928 /* for the nlpid tlv */
929 if (lsp->tlv_data.nlpids) {
930 for (i = 0; i < lsp->tlv_data.nlpids->count; i++) {
931 switch (lsp->tlv_data.nlpids->nlpids[i]) {
932 case NLPID_IP:
933 case NLPID_IPV6:
934 vty_out(vty, " NLPID : 0x%X\n",
935 lsp->tlv_data.nlpids->nlpids[i]);
936 break;
937 default:
938 vty_out(vty, " NLPID : %s\n", "unknown");
939 break;
940 }
941 }
942 }
943
944 for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.mt_router_info, lnode,
945 mt_router_info)) {
946 vty_out(vty, " MT : %s%s\n",
947 isis_mtid2str(mt_router_info->mtid),
948 mt_router_info->overload ? " (overload)" : "");
949 }
950
951 /* for the hostname tlv */
952 if (lsp->tlv_data.hostname) {
953 bzero(hostname, sizeof(hostname));
954 memcpy(hostname, lsp->tlv_data.hostname->name,
955 lsp->tlv_data.hostname->namelen);
956 vty_out(vty, " Hostname : %s\n", hostname);
957 }
958
959 /* authentication tlv */
960 if (lsp->tlv_data.auth_info.type != ISIS_PASSWD_TYPE_UNUSED) {
961 if (lsp->tlv_data.auth_info.type == ISIS_PASSWD_TYPE_HMAC_MD5)
962 vty_out(vty, " Auth type : md5\n");
963 else if (lsp->tlv_data.auth_info.type
964 == ISIS_PASSWD_TYPE_CLEARTXT)
965 vty_out(vty, " Auth type : clear text\n");
966 }
967
968 /* TE router id */
969 if (lsp->tlv_data.router_id) {
970 memcpy(ipv4_address, inet_ntoa(lsp->tlv_data.router_id->id),
971 sizeof(ipv4_address));
972 vty_out(vty, " Router ID : %s\n", ipv4_address);
973 }
974
975 if (lsp->tlv_data.ipv4_addrs)
976 for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.ipv4_addrs, lnode,
977 ipv4_addr)) {
978 memcpy(ipv4_address, inet_ntoa(*ipv4_addr),
979 sizeof(ipv4_address));
980 vty_out(vty, " IPv4 Address: %s\n", ipv4_address);
981 }
982
983 /* for the IS neighbor tlv */
984 if (lsp->tlv_data.is_neighs)
985 for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.is_neighs, lnode,
986 is_neigh)) {
987 lspid_print(is_neigh->neigh_id, LSPid, dynhost, 0);
988 vty_out(vty, " Metric : %-8" PRIu8
989 " IS : %s\n",
990 is_neigh->metrics.metric_default, LSPid);
991 }
992
993 /* for the internal reachable tlv */
994 if (lsp->tlv_data.ipv4_int_reachs)
995 for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.ipv4_int_reachs, lnode,
996 ipv4_reach)) {
997 memcpy(ipv4_reach_prefix, inet_ntoa(ipv4_reach->prefix),
998 sizeof(ipv4_reach_prefix));
999 memcpy(ipv4_reach_mask, inet_ntoa(ipv4_reach->mask),
1000 sizeof(ipv4_reach_mask));
1001 vty_out(vty, " Metric : %-8" PRIu8
1002 " IPv4-Internal : %s %s\n",
1003 ipv4_reach->metrics.metric_default,
1004 ipv4_reach_prefix, ipv4_reach_mask);
1005 }
1006
1007 /* for the external reachable tlv */
1008 if (lsp->tlv_data.ipv4_ext_reachs)
1009 for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.ipv4_ext_reachs, lnode,
1010 ipv4_reach)) {
1011 memcpy(ipv4_reach_prefix, inet_ntoa(ipv4_reach->prefix),
1012 sizeof(ipv4_reach_prefix));
1013 memcpy(ipv4_reach_mask, inet_ntoa(ipv4_reach->mask),
1014 sizeof(ipv4_reach_mask));
1015 vty_out(vty, " Metric : %-8" PRIu8
1016 " IPv4-External : %s %s\n",
1017 ipv4_reach->metrics.metric_default,
1018 ipv4_reach_prefix, ipv4_reach_mask);
1019 }
1020
1021 /* IPv6 tlv */
1022 lsp_print_mt_ipv6_reach(lsp->tlv_data.ipv6_reachs, vty,
1023 ISIS_MT_IPV4_UNICAST);
1024
1025 /* MT IPv6 reachability tlv */
1026 for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.mt_ipv6_reachs, lnode,
1027 mt_ipv6_reachs))
1028 lsp_print_mt_ipv6_reach(mt_ipv6_reachs->list, vty,
1029 mt_ipv6_reachs->mtid);
1030
1031 /* TE IS neighbor tlv */
1032 lsp_print_mt_reach(lsp->tlv_data.te_is_neighs, vty, dynhost,
1033 ISIS_MT_IPV4_UNICAST);
1034
1035 /* MT IS neighbor tlv */
1036 for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.mt_is_neighs, lnode,
1037 mt_is_neigh))
1038 lsp_print_mt_reach(mt_is_neigh->list, vty, dynhost,
1039 mt_is_neigh->mtid);
1040
1041 /* TE IPv4 tlv */
1042 lsp_print_mt_ipv4_reach(lsp->tlv_data.te_ipv4_reachs, vty,
1043 ISIS_MT_IPV4_UNICAST);
1044
1045 /* MT IPv4 reachability tlv */
1046 for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.mt_ipv4_reachs, lnode,
1047 mt_ipv4_reachs))
1048 lsp_print_mt_ipv4_reach(mt_ipv4_reachs->list, vty,
1049 mt_ipv4_reachs->mtid);
1050
1051 vty_out(vty, "\n");
1052
1053 return;
1054 }
1055
1056 /* print all the lsps info in the local lspdb */
1057 int lsp_print_all(struct vty *vty, dict_t *lspdb, char detail, char dynhost)
1058 {
1059
1060 dnode_t *node = dict_first(lspdb), *next;
1061 int lsp_count = 0;
1062
1063 if (detail == ISIS_UI_LEVEL_BRIEF) {
1064 while (node != NULL) {
1065 /* I think it is unnecessary, so I comment it out */
1066 /* dict_contains (lspdb, node); */
1067 next = dict_next(lspdb, node);
1068 lsp_print(dnode_get(node), vty, dynhost);
1069 node = next;
1070 lsp_count++;
1071 }
1072 } else if (detail == ISIS_UI_LEVEL_DETAIL) {
1073 while (node != NULL) {
1074 next = dict_next(lspdb, node);
1075 lsp_print_detail(dnode_get(node), vty, dynhost);
1076 node = next;
1077 lsp_count++;
1078 }
1079 }
1080
1081 return lsp_count;
1082 }
1083
1084 static void _lsp_tlv_fit(struct isis_lsp *lsp, struct list **from,
1085 struct list **to, int frag_thold,
1086 unsigned int tlv_build_func(struct list *,
1087 struct stream *,
1088 void *arg),
1089 void *arg)
1090 {
1091 while (*from && listcount(*from)) {
1092 unsigned int count;
1093
1094 count = tlv_build_func(*from, lsp->pdu, arg);
1095
1096 if (listcount(*to) != 0 || count != listcount(*from)) {
1097 struct listnode *node, *nnode;
1098 void *elem;
1099
1100 for (ALL_LIST_ELEMENTS(*from, node, nnode, elem)) {
1101 if (!count)
1102 break;
1103 listnode_add(*to, elem);
1104 list_delete_node(*from, node);
1105 --count;
1106 }
1107 } else {
1108 list_free(*to);
1109 *to = *from;
1110 *from = NULL;
1111 }
1112 }
1113 }
1114
1115 #define FRAG_THOLD(S, T) ((STREAM_SIZE(S) * T) / 100)
1116
1117 /* stream*, area->lsp_frag_threshold, increment */
1118 #define FRAG_NEEDED(S, T, I) \
1119 (STREAM_SIZE(S) - STREAM_REMAIN(S) + (I) > FRAG_THOLD(S, T))
1120
1121 /* FIXME: It shouldn't be necessary to pass tlvsize here, TLVs can have
1122 * variable length (TE TLVs, sub TLVs). */
1123 static void lsp_tlv_fit(struct isis_lsp *lsp, struct list **from,
1124 struct list **to, int tlvsize, int frag_thold,
1125 int tlv_build_func(struct list *, struct stream *))
1126 {
1127 int count, i;
1128
1129 /* can we fit all ? */
1130 if (!FRAG_NEEDED(lsp->pdu, frag_thold,
1131 listcount(*from) * tlvsize + 2)) {
1132 tlv_build_func(*from, lsp->pdu);
1133 if (listcount(*to) != 0) {
1134 struct listnode *node, *nextnode;
1135 void *elem;
1136
1137 for (ALL_LIST_ELEMENTS(*from, node, nextnode, elem)) {
1138 listnode_add(*to, elem);
1139 list_delete_node(*from, node);
1140 }
1141 } else {
1142 list_free(*to);
1143 *to = *from;
1144 *from = NULL;
1145 }
1146 } else if (!FRAG_NEEDED(lsp->pdu, frag_thold, tlvsize + 2)) {
1147 /* fit all we can */
1148 count = FRAG_THOLD(lsp->pdu, frag_thold) - 2
1149 - (STREAM_SIZE(lsp->pdu) - STREAM_REMAIN(lsp->pdu));
1150 count = count / tlvsize;
1151 if (count > (int)listcount(*from))
1152 count = listcount(*from);
1153 for (i = 0; i < count; i++) {
1154 listnode_add(*to, listgetdata(listhead(*from)));
1155 listnode_delete(*from, listgetdata(listhead(*from)));
1156 }
1157 tlv_build_func(*to, lsp->pdu);
1158 }
1159 lsp->lsp_header->pdu_len = htons(stream_get_endp(lsp->pdu));
1160 return;
1161 }
1162
1163 static u_int16_t lsp_rem_lifetime(struct isis_area *area, int level)
1164 {
1165 u_int16_t rem_lifetime;
1166
1167 /* Add jitter to configured LSP lifetime */
1168 rem_lifetime =
1169 isis_jitter(area->max_lsp_lifetime[level - 1], MAX_AGE_JITTER);
1170
1171 /* No jitter if the max refresh will be less than configure gen interval
1172 */
1173 /* N.B. this calucation is acceptable since rem_lifetime is in
1174 * [332,65535] at
1175 * this point */
1176 if (area->lsp_gen_interval[level - 1] > (rem_lifetime - 300))
1177 rem_lifetime = area->max_lsp_lifetime[level - 1];
1178
1179 return rem_lifetime;
1180 }
1181
1182 static u_int16_t lsp_refresh_time(struct isis_lsp *lsp, u_int16_t rem_lifetime)
1183 {
1184 struct isis_area *area = lsp->area;
1185 int level = lsp->level;
1186 u_int16_t refresh_time;
1187
1188 /* Add jitter to LSP refresh time */
1189 refresh_time =
1190 isis_jitter(area->lsp_refresh[level - 1], MAX_LSP_GEN_JITTER);
1191
1192 /* RFC 4444 : make sure the refresh time is at least less than 300
1193 * of the remaining lifetime and more than gen interval */
1194 if (refresh_time <= area->lsp_gen_interval[level - 1]
1195 || refresh_time > (rem_lifetime - 300))
1196 refresh_time = rem_lifetime - 300;
1197
1198 /* In cornercases, refresh_time might be <= lsp_gen_interval, however
1199 * we accept this violation to satisfy refresh_time <= rem_lifetime -
1200 * 300 */
1201
1202 return refresh_time;
1203 }
1204
1205 static struct isis_lsp *lsp_next_frag(u_char frag_num, struct isis_lsp *lsp0,
1206 struct isis_area *area, int level)
1207 {
1208 struct isis_lsp *lsp;
1209 u_char frag_id[ISIS_SYS_ID_LEN + 2];
1210
1211 memcpy(frag_id, lsp0->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 1);
1212 LSP_FRAGMENT(frag_id) = frag_num;
1213 /* FIXME add authentication TLV for fragment LSPs */
1214 lsp = lsp_search(frag_id, area->lspdb[level - 1]);
1215 if (lsp) {
1216 /* Clear the TLVs */
1217 lsp_clear_data(lsp);
1218 return lsp;
1219 }
1220 lsp = lsp_new(area, frag_id, ntohs(lsp0->lsp_header->rem_lifetime), 0,
1221 lsp_bits_generate(level, area->overload_bit,
1222 area->attached_bit),
1223 0, level);
1224 lsp->area = area;
1225 lsp->own_lsp = 1;
1226 lsp_insert(lsp, area->lspdb[level - 1]);
1227 listnode_add(lsp0->lspu.frags, lsp);
1228 lsp->lspu.zero_lsp = lsp0;
1229 return lsp;
1230 }
1231
1232 static void lsp_build_ext_reach_ipv4(struct isis_lsp *lsp,
1233 struct isis_area *area,
1234 struct tlvs *tlv_data)
1235 {
1236 struct route_table *er_table;
1237 struct route_node *rn;
1238 struct prefix_ipv4 *ipv4;
1239 struct isis_ext_info *info;
1240 struct ipv4_reachability *ipreach;
1241 struct te_ipv4_reachability *te_ipreach;
1242
1243 er_table = get_ext_reach(area, AF_INET, lsp->level);
1244 if (!er_table)
1245 return;
1246
1247 for (rn = route_top(er_table); rn; rn = route_next(rn)) {
1248 if (!rn->info)
1249 continue;
1250
1251 ipv4 = (struct prefix_ipv4 *)&rn->p;
1252 info = rn->info;
1253 if (area->oldmetric) {
1254 if (tlv_data->ipv4_ext_reachs == NULL) {
1255 tlv_data->ipv4_ext_reachs = list_new();
1256 tlv_data->ipv4_ext_reachs->del = free_tlv;
1257 }
1258 ipreach = XMALLOC(MTYPE_ISIS_TLV, sizeof(*ipreach));
1259
1260 ipreach->prefix.s_addr = ipv4->prefix.s_addr;
1261 masklen2ip(ipv4->prefixlen, &ipreach->mask);
1262 ipreach->prefix.s_addr &= ipreach->mask.s_addr;
1263
1264 if ((info->metric & 0x3f) != info->metric)
1265 ipreach->metrics.metric_default = 0x3f;
1266 else
1267 ipreach->metrics.metric_default = info->metric;
1268 ipreach->metrics.metric_expense = METRICS_UNSUPPORTED;
1269 ipreach->metrics.metric_error = METRICS_UNSUPPORTED;
1270 ipreach->metrics.metric_delay = METRICS_UNSUPPORTED;
1271 listnode_add(tlv_data->ipv4_ext_reachs, ipreach);
1272 }
1273 if (area->newmetric) {
1274 if (tlv_data->te_ipv4_reachs == NULL) {
1275 tlv_data->te_ipv4_reachs = list_new();
1276 tlv_data->te_ipv4_reachs->del = free_tlv;
1277 }
1278 te_ipreach = XCALLOC(MTYPE_ISIS_TLV,
1279 sizeof(*te_ipreach) - 1
1280 + PSIZE(ipv4->prefixlen));
1281 if (info->metric > MAX_WIDE_PATH_METRIC)
1282 te_ipreach->te_metric =
1283 htonl(MAX_WIDE_PATH_METRIC);
1284 else
1285 te_ipreach->te_metric = htonl(info->metric);
1286 te_ipreach->control = ipv4->prefixlen & 0x3f;
1287 memcpy(&te_ipreach->prefix_start, &ipv4->prefix.s_addr,
1288 PSIZE(ipv4->prefixlen));
1289 listnode_add(tlv_data->te_ipv4_reachs, te_ipreach);
1290 }
1291 }
1292 }
1293
1294 static struct list *tlv_get_ipv6_reach_list(struct isis_area *area,
1295 struct tlvs *tlv_data)
1296 {
1297 uint16_t mtid = isis_area_ipv6_topology(area);
1298 if (mtid == ISIS_MT_IPV4_UNICAST) {
1299 if (!tlv_data->ipv6_reachs) {
1300 tlv_data->ipv6_reachs = list_new();
1301 tlv_data->ipv6_reachs->del = free_tlv;
1302 }
1303 return tlv_data->ipv6_reachs;
1304 }
1305
1306 struct tlv_mt_ipv6_reachs *reachs =
1307 tlvs_get_mt_ipv6_reachs(tlv_data, mtid);
1308 return reachs->list;
1309 }
1310
1311 static void lsp_build_ext_reach_ipv6(struct isis_lsp *lsp,
1312 struct isis_area *area,
1313 struct tlvs *tlv_data)
1314 {
1315 struct route_table *er_table;
1316 struct route_node *rn;
1317 struct prefix_ipv6 *ipv6;
1318 struct isis_ext_info *info;
1319 struct ipv6_reachability *ip6reach;
1320 struct list *reach_list = NULL;
1321
1322 er_table = get_ext_reach(area, AF_INET6, lsp->level);
1323 if (!er_table)
1324 return;
1325
1326 for (rn = route_top(er_table); rn; rn = route_next(rn)) {
1327 if (!rn->info)
1328 continue;
1329
1330 ipv6 = (struct prefix_ipv6 *)&rn->p;
1331 info = rn->info;
1332
1333 if (!reach_list)
1334 reach_list = tlv_get_ipv6_reach_list(area, tlv_data);
1335
1336 ip6reach = XCALLOC(MTYPE_ISIS_TLV, sizeof(*ip6reach));
1337 if (info->metric > MAX_WIDE_PATH_METRIC)
1338 ip6reach->metric = htonl(MAX_WIDE_PATH_METRIC);
1339 else
1340 ip6reach->metric = htonl(info->metric);
1341 ip6reach->control_info = DISTRIBUTION_EXTERNAL;
1342 ip6reach->prefix_len = ipv6->prefixlen;
1343 memcpy(ip6reach->prefix, ipv6->prefix.s6_addr,
1344 sizeof(ip6reach->prefix));
1345 listnode_add(reach_list, ip6reach);
1346 }
1347 }
1348
1349 static void lsp_build_ext_reach(struct isis_lsp *lsp, struct isis_area *area,
1350 struct tlvs *tlv_data)
1351 {
1352 lsp_build_ext_reach_ipv4(lsp, area, tlv_data);
1353 lsp_build_ext_reach_ipv6(lsp, area, tlv_data);
1354 }
1355
1356 /*
1357 * Builds the LSP data part. This func creates a new frag whenever
1358 * area->lsp_frag_threshold is exceeded.
1359 */
1360 static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
1361 {
1362 struct is_neigh *is_neigh;
1363 struct te_is_neigh *te_is_neigh;
1364 struct listnode *node, *ipnode;
1365 int level = lsp->level;
1366 struct isis_circuit *circuit;
1367 struct prefix_ipv4 *ipv4;
1368 struct ipv4_reachability *ipreach;
1369 struct te_ipv4_reachability *te_ipreach;
1370 struct isis_adjacency *nei;
1371 struct prefix_ipv6 *ipv6, ip6prefix;
1372 struct list *ipv6_reachs = NULL;
1373 struct ipv6_reachability *ip6reach;
1374 struct tlvs tlv_data;
1375 struct isis_lsp *lsp0 = lsp;
1376 struct in_addr *routerid;
1377 uint32_t expected = 0, found = 0;
1378 uint32_t metric;
1379 u_char zero_id[ISIS_SYS_ID_LEN + 1];
1380 int retval = ISIS_OK;
1381 char buf[BUFSIZ];
1382
1383 lsp_debug("ISIS (%s): Constructing local system LSP for level %d",
1384 area->area_tag, level);
1385
1386 /*
1387 * Building the zero lsp
1388 */
1389 memset(zero_id, 0, ISIS_SYS_ID_LEN + 1);
1390
1391 /* Reset stream endp. Stream is always there and on every LSP refresh
1392 * only
1393 * TLV part of it is overwritten. So we must seek past header we will
1394 * not
1395 * touch. */
1396 stream_reset(lsp->pdu);
1397 stream_forward_endp(lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
1398
1399 /*
1400 * Add the authentication info if its present
1401 */
1402 lsp_auth_add(lsp);
1403
1404 /*
1405 * First add the tlvs related to area
1406 */
1407
1408 /* Area addresses */
1409 if (lsp->tlv_data.area_addrs == NULL)
1410 lsp->tlv_data.area_addrs = list_new();
1411 list_add_list(lsp->tlv_data.area_addrs, area->area_addrs);
1412 if (listcount(lsp->tlv_data.area_addrs) > 0)
1413 tlv_add_area_addrs(lsp->tlv_data.area_addrs, lsp->pdu);
1414
1415 /* Protocols Supported */
1416 if (area->ip_circuits > 0 || area->ipv6_circuits > 0) {
1417 lsp->tlv_data.nlpids =
1418 XCALLOC(MTYPE_ISIS_TLV, sizeof(struct nlpids));
1419 lsp->tlv_data.nlpids->count = 0;
1420 if (area->ip_circuits > 0) {
1421 lsp_debug(
1422 "ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs",
1423 area->area_tag);
1424 lsp->tlv_data.nlpids->count++;
1425 lsp->tlv_data.nlpids->nlpids[0] = NLPID_IP;
1426 }
1427 if (area->ipv6_circuits > 0) {
1428 lsp_debug(
1429 "ISIS (%s): Found IPv6 circuit, adding IPv6 to NLPIDs",
1430 area->area_tag);
1431 lsp->tlv_data.nlpids->count++;
1432 lsp->tlv_data.nlpids
1433 ->nlpids[lsp->tlv_data.nlpids->count - 1] =
1434 NLPID_IPV6;
1435 }
1436 tlv_add_nlpid(lsp->tlv_data.nlpids, lsp->pdu);
1437 }
1438
1439 if (area_is_mt(area)) {
1440 lsp_debug("ISIS (%s): Adding MT router tlv...", area->area_tag);
1441 lsp->tlv_data.mt_router_info = list_new();
1442 lsp->tlv_data.mt_router_info->del = free_tlv;
1443
1444 struct isis_area_mt_setting **mt_settings;
1445 unsigned int mt_count;
1446
1447 mt_settings = area_mt_settings(area, &mt_count);
1448 for (unsigned int i = 0; i < mt_count; i++) {
1449 struct mt_router_info *info;
1450
1451 info = XCALLOC(MTYPE_ISIS_TLV, sizeof(*info));
1452 info->mtid = mt_settings[i]->mtid;
1453 info->overload = mt_settings[i]->overload;
1454 listnode_add(lsp->tlv_data.mt_router_info, info);
1455 lsp_debug("ISIS (%s): MT %s", area->area_tag,
1456 isis_mtid2str(info->mtid));
1457 }
1458 tlv_add_mt_router_info(lsp->tlv_data.mt_router_info, lsp->pdu);
1459 } else {
1460 lsp_debug("ISIS (%s): Not adding MT router tlv (disabled)",
1461 area->area_tag);
1462 }
1463 /* Dynamic Hostname */
1464 if (area->dynhostname) {
1465 const char *hostname = unix_hostname();
1466 size_t hostname_len = strlen(hostname);
1467
1468 lsp->tlv_data.hostname =
1469 XMALLOC(MTYPE_ISIS_TLV, sizeof(struct hostname));
1470
1471 strncpy((char *)lsp->tlv_data.hostname->name, hostname,
1472 sizeof(lsp->tlv_data.hostname->name));
1473 if (hostname_len <= MAX_TLV_LEN)
1474 lsp->tlv_data.hostname->namelen = hostname_len;
1475 else
1476 lsp->tlv_data.hostname->namelen = MAX_TLV_LEN;
1477
1478 lsp_debug("ISIS (%s): Adding dynamic hostname '%.*s'",
1479 area->area_tag, lsp->tlv_data.hostname->namelen,
1480 lsp->tlv_data.hostname->name);
1481 tlv_add_dynamic_hostname(lsp->tlv_data.hostname, lsp->pdu);
1482 } else {
1483 lsp_debug("ISIS (%s): Not adding dynamic hostname (disabled)",
1484 area->area_tag);
1485 }
1486
1487 /* IPv4 address and TE router ID TLVs. In case of the first one we don't
1488 * follow "C" vendor, but "J" vendor behavior - one IPv4 address is put
1489 * into
1490 * LSP and this address is same as router id. */
1491 if (isis->router_id != 0) {
1492 inet_ntop(AF_INET, &isis->router_id, buf, sizeof(buf));
1493 lsp_debug("ISIS (%s): Adding router ID %s as IPv4 tlv.",
1494 area->area_tag, buf);
1495 if (lsp->tlv_data.ipv4_addrs == NULL) {
1496 lsp->tlv_data.ipv4_addrs = list_new();
1497 lsp->tlv_data.ipv4_addrs->del = free_tlv;
1498 }
1499
1500 routerid = XMALLOC(MTYPE_ISIS_TLV, sizeof(struct in_addr));
1501 routerid->s_addr = isis->router_id;
1502 listnode_add(lsp->tlv_data.ipv4_addrs, routerid);
1503 tlv_add_in_addr(routerid, lsp->pdu, IPV4_ADDR);
1504
1505 /* Exactly same data is put into TE router ID TLV, but only if
1506 * new style
1507 * TLV's are in use. */
1508 if (area->newmetric) {
1509 lsp_debug(
1510 "ISIS (%s): Adding router ID also as TE router ID tlv.",
1511 area->area_tag);
1512 lsp->tlv_data.router_id =
1513 XMALLOC(MTYPE_ISIS_TLV, sizeof(struct in_addr));
1514 lsp->tlv_data.router_id->id.s_addr = isis->router_id;
1515 tlv_add_in_addr(&lsp->tlv_data.router_id->id, lsp->pdu,
1516 TE_ROUTER_ID);
1517 }
1518 } else {
1519 lsp_debug("ISIS (%s): Router ID is unset. Not adding tlv.",
1520 area->area_tag);
1521 }
1522
1523 memset(&tlv_data, 0, sizeof(struct tlvs));
1524
1525 lsp_debug("ISIS (%s): Adding circuit specific information.",
1526 area->area_tag);
1527
1528 /*
1529 * Then build lists of tlvs related to circuits
1530 */
1531 for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
1532 if (!circuit->interface)
1533 lsp_debug(
1534 "ISIS (%s): Processing %s circuit %p with unknown interface",
1535 area->area_tag,
1536 circuit_type2string(circuit->circ_type),
1537 circuit);
1538 else
1539 lsp_debug("ISIS (%s): Processing %s circuit %s",
1540 area->area_tag,
1541 circuit_type2string(circuit->circ_type),
1542 circuit->interface->name);
1543
1544 if (circuit->state != C_STATE_UP) {
1545 lsp_debug("ISIS (%s): Circuit is not up, ignoring.",
1546 area->area_tag);
1547 continue;
1548 }
1549
1550 /*
1551 * Add IPv4 internal reachability of this circuit
1552 */
1553 if (circuit->ip_router && circuit->ip_addrs
1554 && circuit->ip_addrs->count > 0) {
1555 lsp_debug(
1556 "ISIS (%s): Circuit has IPv4 active, adding respective TLVs.",
1557 area->area_tag);
1558 if (area->oldmetric) {
1559 if (tlv_data.ipv4_int_reachs == NULL) {
1560 tlv_data.ipv4_int_reachs = list_new();
1561 tlv_data.ipv4_int_reachs->del =
1562 free_tlv;
1563 }
1564 for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs,
1565 ipnode, ipv4)) {
1566 ipreach = XMALLOC(
1567 MTYPE_ISIS_TLV,
1568 sizeof(struct
1569 ipv4_reachability));
1570 ipreach->metrics.metric_default =
1571 circuit->metric[level - 1];
1572 ipreach->metrics.metric_expense =
1573 METRICS_UNSUPPORTED;
1574 ipreach->metrics.metric_error =
1575 METRICS_UNSUPPORTED;
1576 ipreach->metrics.metric_delay =
1577 METRICS_UNSUPPORTED;
1578 masklen2ip(ipv4->prefixlen,
1579 &ipreach->mask);
1580 ipreach->prefix.s_addr =
1581 ((ipreach->mask.s_addr)
1582 & (ipv4->prefix.s_addr));
1583 inet_ntop(AF_INET,
1584 &ipreach->prefix.s_addr, buf,
1585 sizeof(buf));
1586 lsp_debug(
1587 "ISIS (%s): Adding old-style IP reachability for %s/%d",
1588 area->area_tag, buf,
1589 ipv4->prefixlen);
1590 listnode_add(tlv_data.ipv4_int_reachs,
1591 ipreach);
1592 }
1593 }
1594 if (area->newmetric) {
1595 if (tlv_data.te_ipv4_reachs == NULL) {
1596 tlv_data.te_ipv4_reachs = list_new();
1597 tlv_data.te_ipv4_reachs->del = free_tlv;
1598 }
1599 for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs,
1600 ipnode, ipv4)) {
1601 /* FIXME All this assumes that we have
1602 * no sub TLVs. */
1603 te_ipreach = XCALLOC(
1604 MTYPE_ISIS_TLV,
1605 sizeof(struct
1606 te_ipv4_reachability)
1607 + ((ipv4->prefixlen + 7)
1608 / 8)
1609 - 1);
1610
1611 if (area->oldmetric)
1612 te_ipreach->te_metric = htonl(
1613 circuit->metric[level
1614 - 1]);
1615 else
1616 te_ipreach->te_metric = htonl(
1617 circuit->te_metric
1618 [level - 1]);
1619
1620 te_ipreach->control =
1621 (ipv4->prefixlen & 0x3F);
1622 memcpy(&te_ipreach->prefix_start,
1623 &ipv4->prefix.s_addr,
1624 (ipv4->prefixlen + 7) / 8);
1625 inet_ntop(AF_INET, &ipv4->prefix.s_addr,
1626 buf, sizeof(buf));
1627 lsp_debug(
1628 "ISIS (%s): Adding te-style IP reachability for %s/%d",
1629 area->area_tag, buf,
1630 ipv4->prefixlen);
1631 listnode_add(tlv_data.te_ipv4_reachs,
1632 te_ipreach);
1633 }
1634 }
1635 }
1636
1637 /*
1638 * Add IPv6 reachability of this circuit
1639 */
1640 if (circuit->ipv6_router && circuit->ipv6_non_link
1641 && circuit->ipv6_non_link->count > 0) {
1642 if (!ipv6_reachs)
1643 ipv6_reachs = tlv_get_ipv6_reach_list(
1644 area, &tlv_data);
1645
1646 for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link,
1647 ipnode, ipv6)) {
1648 ip6reach = XCALLOC(
1649 MTYPE_ISIS_TLV,
1650 sizeof(struct ipv6_reachability));
1651
1652 if (area->oldmetric)
1653 ip6reach->metric = htonl(
1654 circuit->metric[level - 1]);
1655 else
1656 ip6reach->metric = htonl(
1657 circuit->te_metric[level - 1]);
1658
1659 ip6reach->control_info = 0;
1660 ip6reach->prefix_len = ipv6->prefixlen;
1661 memcpy(&ip6prefix, ipv6, sizeof(ip6prefix));
1662 apply_mask_ipv6(&ip6prefix);
1663
1664 inet_ntop(AF_INET6, &ip6prefix.prefix.s6_addr,
1665 buf, sizeof(buf));
1666 lsp_debug(
1667 "ISIS (%s): Adding IPv6 reachability for %s/%d",
1668 area->area_tag, buf, ipv6->prefixlen);
1669
1670 memcpy(ip6reach->prefix,
1671 ip6prefix.prefix.s6_addr,
1672 sizeof(ip6reach->prefix));
1673 listnode_add(ipv6_reachs, ip6reach);
1674 }
1675 }
1676
1677 switch (circuit->circ_type) {
1678 case CIRCUIT_T_BROADCAST:
1679 if (level & circuit->is_type) {
1680 if (area->oldmetric) {
1681 if (tlv_data.is_neighs == NULL) {
1682 tlv_data.is_neighs = list_new();
1683 tlv_data.is_neighs->del =
1684 free_tlv;
1685 }
1686 is_neigh = XCALLOC(
1687 MTYPE_ISIS_TLV,
1688 sizeof(struct is_neigh));
1689 if (level == IS_LEVEL_1)
1690 memcpy(is_neigh->neigh_id,
1691 circuit->u.bc
1692 .l1_desig_is,
1693 ISIS_SYS_ID_LEN + 1);
1694 else
1695 memcpy(is_neigh->neigh_id,
1696 circuit->u.bc
1697 .l2_desig_is,
1698 ISIS_SYS_ID_LEN + 1);
1699 is_neigh->metrics.metric_default =
1700 circuit->metric[level - 1];
1701 is_neigh->metrics.metric_expense =
1702 METRICS_UNSUPPORTED;
1703 is_neigh->metrics.metric_error =
1704 METRICS_UNSUPPORTED;
1705 is_neigh->metrics.metric_delay =
1706 METRICS_UNSUPPORTED;
1707 if (!memcmp(is_neigh->neigh_id, zero_id,
1708 ISIS_SYS_ID_LEN + 1)) {
1709 XFREE(MTYPE_ISIS_TLV, is_neigh);
1710 lsp_debug(
1711 "ISIS (%s): No DIS for circuit, not adding old-style IS neighbor.",
1712 area->area_tag);
1713 } else {
1714 listnode_add(tlv_data.is_neighs,
1715 is_neigh);
1716 lsp_debug(
1717 "ISIS (%s): Adding DIS %s.%02x as old-style neighbor",
1718 area->area_tag,
1719 sysid_print(
1720 is_neigh->neigh_id),
1721 LSP_PSEUDO_ID(
1722 is_neigh->neigh_id));
1723 }
1724 }
1725 if (area->newmetric) {
1726 if (tlv_data.te_is_neighs == NULL) {
1727 tlv_data.te_is_neighs =
1728 list_new();
1729 tlv_data.te_is_neighs->del =
1730 free_tlv;
1731 }
1732 te_is_neigh = XCALLOC(
1733 MTYPE_ISIS_TLV,
1734 sizeof(struct te_is_neigh));
1735 if (level == IS_LEVEL_1)
1736 memcpy(te_is_neigh->neigh_id,
1737 circuit->u.bc
1738 .l1_desig_is,
1739 ISIS_SYS_ID_LEN + 1);
1740 else
1741 memcpy(te_is_neigh->neigh_id,
1742 circuit->u.bc
1743 .l2_desig_is,
1744 ISIS_SYS_ID_LEN + 1);
1745 if (area->oldmetric)
1746 metric = circuit->metric[level
1747 - 1];
1748 else
1749 metric =
1750 circuit->te_metric[level
1751 - 1];
1752 SET_TE_METRIC(te_is_neigh, metric);
1753 if (!memcmp(te_is_neigh->neigh_id,
1754 zero_id,
1755 ISIS_SYS_ID_LEN + 1)) {
1756 XFREE(MTYPE_ISIS_TLV,
1757 te_is_neigh);
1758 lsp_debug(
1759 "ISIS (%s): No DIS for circuit, not adding te-style IS neighbor.",
1760 area->area_tag);
1761 } else {
1762 /* Check if MPLS_TE is activate
1763 */
1764 if (IS_MPLS_TE(isisMplsTE)
1765 && HAS_LINK_PARAMS(
1766 circuit->interface))
1767 /* Add SubTLVs & Adjust
1768 * real size of SubTLVs
1769 */
1770 te_is_neigh
1771 ->sub_tlvs_length = add_te_subtlvs(
1772 te_is_neigh
1773 ->sub_tlvs,
1774 circuit->mtc);
1775 else
1776 /* Or keep only TE
1777 * metric with no
1778 * SubTLVs if MPLS_TE is
1779 * off */
1780 te_is_neigh
1781 ->sub_tlvs_length =
1782 0;
1783
1784 tlvs_add_mt_bcast(
1785 &tlv_data, circuit,
1786 level, te_is_neigh);
1787 XFREE(MTYPE_ISIS_TLV,
1788 te_is_neigh);
1789 }
1790 }
1791 } else {
1792 lsp_debug(
1793 "ISIS (%s): Circuit is not active for current level. Not adding IS neighbors",
1794 area->area_tag);
1795 }
1796 break;
1797 case CIRCUIT_T_P2P:
1798 nei = circuit->u.p2p.neighbor;
1799 if (nei && (level & nei->circuit_t)) {
1800 if (area->oldmetric) {
1801 if (tlv_data.is_neighs == NULL) {
1802 tlv_data.is_neighs = list_new();
1803 tlv_data.is_neighs->del =
1804 free_tlv;
1805 }
1806 is_neigh = XCALLOC(
1807 MTYPE_ISIS_TLV,
1808 sizeof(struct is_neigh));
1809 memcpy(is_neigh->neigh_id, nei->sysid,
1810 ISIS_SYS_ID_LEN);
1811 is_neigh->metrics.metric_default =
1812 circuit->metric[level - 1];
1813 is_neigh->metrics.metric_expense =
1814 METRICS_UNSUPPORTED;
1815 is_neigh->metrics.metric_error =
1816 METRICS_UNSUPPORTED;
1817 is_neigh->metrics.metric_delay =
1818 METRICS_UNSUPPORTED;
1819 listnode_add(tlv_data.is_neighs,
1820 is_neigh);
1821 lsp_debug(
1822 "ISIS (%s): Adding old-style is reach for %s",
1823 area->area_tag,
1824 sysid_print(
1825 is_neigh->neigh_id));
1826 }
1827 if (area->newmetric) {
1828 uint32_t metric;
1829
1830 if (tlv_data.te_is_neighs == NULL) {
1831 tlv_data.te_is_neighs =
1832 list_new();
1833 tlv_data.te_is_neighs->del =
1834 free_tlv;
1835 }
1836 te_is_neigh = XCALLOC(
1837 MTYPE_ISIS_TLV,
1838 sizeof(struct te_is_neigh));
1839 memcpy(te_is_neigh->neigh_id,
1840 nei->sysid, ISIS_SYS_ID_LEN);
1841 metric = circuit->te_metric[level - 1];
1842 SET_TE_METRIC(te_is_neigh, metric);
1843 /* Check if MPLS_TE is activate */
1844 if (IS_MPLS_TE(isisMplsTE)
1845 && HAS_LINK_PARAMS(
1846 circuit->interface))
1847 /* Update Local and Remote IP
1848 * address for MPLS TE circuit
1849 * parameters */
1850 /* NOTE sure that it is the
1851 * pertinent place for that
1852 * updates */
1853 /* Local IP address could be
1854 * updated in isis_circuit.c -
1855 * isis_circuit_add_addr() */
1856 /* But, where update remote IP
1857 * address ? in isis_pdu.c -
1858 * process_p2p_hello() ? */
1859
1860 /* Add SubTLVs & Adjust real
1861 * size of SubTLVs */
1862 te_is_neigh->sub_tlvs_length =
1863 add_te_subtlvs(
1864 te_is_neigh
1865 ->sub_tlvs,
1866 circuit->mtc);
1867 else
1868 /* Or keep only TE metric with
1869 * no SubTLVs if MPLS_TE is off
1870 */
1871 te_is_neigh->sub_tlvs_length =
1872 0;
1873
1874 tlvs_add_mt_p2p(&tlv_data, circuit,
1875 te_is_neigh);
1876 XFREE(MTYPE_ISIS_TLV, te_is_neigh);
1877 }
1878 } else {
1879 lsp_debug(
1880 "ISIS (%s): No adjacency for given level on this circuit. Not adding IS neighbors",
1881 area->area_tag);
1882 }
1883 break;
1884 case CIRCUIT_T_LOOPBACK:
1885 break;
1886 default:
1887 zlog_warn("lsp_area_create: unknown circuit type");
1888 }
1889 }
1890
1891 lsp_build_ext_reach(lsp, area, &tlv_data);
1892
1893 lsp_debug("ISIS (%s): LSP construction is complete. Serializing...",
1894 area->area_tag);
1895
1896 while (tlv_data.ipv4_int_reachs
1897 && listcount(tlv_data.ipv4_int_reachs)) {
1898 if (lsp->tlv_data.ipv4_int_reachs == NULL)
1899 lsp->tlv_data.ipv4_int_reachs = list_new();
1900 lsp_tlv_fit(lsp, &tlv_data.ipv4_int_reachs,
1901 &lsp->tlv_data.ipv4_int_reachs, IPV4_REACH_LEN,
1902 area->lsp_frag_threshold, tlv_add_ipv4_int_reachs);
1903 if (tlv_data.ipv4_int_reachs
1904 && listcount(tlv_data.ipv4_int_reachs))
1905 lsp = lsp_next_frag(
1906 LSP_FRAGMENT(lsp->lsp_header->lsp_id) + 1, lsp0,
1907 area, level);
1908 }
1909
1910 while (tlv_data.ipv4_ext_reachs
1911 && listcount(tlv_data.ipv4_ext_reachs)) {
1912 if (lsp->tlv_data.ipv4_ext_reachs == NULL)
1913 lsp->tlv_data.ipv4_ext_reachs = list_new();
1914 lsp_tlv_fit(lsp, &tlv_data.ipv4_ext_reachs,
1915 &lsp->tlv_data.ipv4_ext_reachs, IPV4_REACH_LEN,
1916 area->lsp_frag_threshold, tlv_add_ipv4_ext_reachs);
1917 if (tlv_data.ipv4_ext_reachs
1918 && listcount(tlv_data.ipv4_ext_reachs))
1919 lsp = lsp_next_frag(
1920 LSP_FRAGMENT(lsp->lsp_header->lsp_id) + 1, lsp0,
1921 area, level);
1922 }
1923
1924 while (tlv_data.te_ipv4_reachs && listcount(tlv_data.te_ipv4_reachs)) {
1925 if (lsp->tlv_data.te_ipv4_reachs == NULL)
1926 lsp->tlv_data.te_ipv4_reachs = list_new();
1927 _lsp_tlv_fit(lsp, &tlv_data.te_ipv4_reachs,
1928 &lsp->tlv_data.te_ipv4_reachs,
1929 area->lsp_frag_threshold, tlv_add_te_ipv4_reachs,
1930 NULL);
1931 if (tlv_data.te_ipv4_reachs
1932 && listcount(tlv_data.te_ipv4_reachs))
1933 lsp = lsp_next_frag(
1934 LSP_FRAGMENT(lsp->lsp_header->lsp_id) + 1, lsp0,
1935 area, level);
1936 }
1937
1938 struct tlv_mt_ipv4_reachs *mt_ipv4_reachs;
1939 for (ALL_LIST_ELEMENTS_RO(tlv_data.mt_ipv4_reachs, node,
1940 mt_ipv4_reachs)) {
1941 while (mt_ipv4_reachs->list
1942 && listcount(mt_ipv4_reachs->list)) {
1943 struct tlv_mt_ipv4_reachs *frag_mt_ipv4_reachs;
1944
1945 frag_mt_ipv4_reachs = tlvs_get_mt_ipv4_reachs(
1946 &lsp->tlv_data, mt_ipv4_reachs->mtid);
1947 _lsp_tlv_fit(lsp, &mt_ipv4_reachs->list,
1948 &frag_mt_ipv4_reachs->list,
1949 area->lsp_frag_threshold,
1950 tlv_add_te_ipv4_reachs,
1951 &mt_ipv4_reachs->mtid);
1952 if (mt_ipv4_reachs->list
1953 && listcount(mt_ipv4_reachs->list))
1954 lsp = lsp_next_frag(
1955 LSP_FRAGMENT(lsp->lsp_header->lsp_id)
1956 + 1,
1957 lsp0, area, level);
1958 }
1959 }
1960
1961 while (tlv_data.ipv6_reachs && listcount(tlv_data.ipv6_reachs)) {
1962 if (lsp->tlv_data.ipv6_reachs == NULL)
1963 lsp->tlv_data.ipv6_reachs = list_new();
1964 _lsp_tlv_fit(
1965 lsp, &tlv_data.ipv6_reachs, &lsp->tlv_data.ipv6_reachs,
1966 area->lsp_frag_threshold, tlv_add_ipv6_reachs, NULL);
1967 if (tlv_data.ipv6_reachs && listcount(tlv_data.ipv6_reachs))
1968 lsp = lsp_next_frag(
1969 LSP_FRAGMENT(lsp->lsp_header->lsp_id) + 1, lsp0,
1970 area, level);
1971 }
1972
1973 struct tlv_mt_ipv6_reachs *mt_ipv6_reachs;
1974 for (ALL_LIST_ELEMENTS_RO(tlv_data.mt_ipv6_reachs, node,
1975 mt_ipv6_reachs)) {
1976 while (mt_ipv6_reachs->list
1977 && listcount(mt_ipv6_reachs->list)) {
1978 struct tlv_mt_ipv6_reachs *frag_mt_ipv6_reachs;
1979
1980 frag_mt_ipv6_reachs = tlvs_get_mt_ipv6_reachs(
1981 &lsp->tlv_data, mt_ipv6_reachs->mtid);
1982 _lsp_tlv_fit(lsp, &mt_ipv6_reachs->list,
1983 &frag_mt_ipv6_reachs->list,
1984 area->lsp_frag_threshold,
1985 tlv_add_ipv6_reachs,
1986 &mt_ipv6_reachs->mtid);
1987 if (mt_ipv6_reachs->list
1988 && listcount(mt_ipv6_reachs->list))
1989 lsp = lsp_next_frag(
1990 LSP_FRAGMENT(lsp->lsp_header->lsp_id)
1991 + 1,
1992 lsp0, area, level);
1993 }
1994 }
1995
1996 while (tlv_data.is_neighs && listcount(tlv_data.is_neighs)) {
1997 if (lsp->tlv_data.is_neighs == NULL)
1998 lsp->tlv_data.is_neighs = list_new();
1999 lsp_tlv_fit(lsp, &tlv_data.is_neighs, &lsp->tlv_data.is_neighs,
2000 IS_NEIGHBOURS_LEN, area->lsp_frag_threshold,
2001 tlv_add_is_neighs);
2002 if (tlv_data.is_neighs && listcount(tlv_data.is_neighs))
2003 lsp = lsp_next_frag(
2004 LSP_FRAGMENT(lsp->lsp_header->lsp_id) + 1, lsp0,
2005 area, level);
2006 }
2007
2008 while (tlv_data.te_is_neighs && listcount(tlv_data.te_is_neighs)) {
2009 if (lsp->tlv_data.te_is_neighs == NULL)
2010 lsp->tlv_data.te_is_neighs = list_new();
2011 _lsp_tlv_fit(lsp, &tlv_data.te_is_neighs,
2012 &lsp->tlv_data.te_is_neighs,
2013 area->lsp_frag_threshold, tlv_add_te_is_neighs,
2014 NULL);
2015 if (tlv_data.te_is_neighs && listcount(tlv_data.te_is_neighs))
2016 lsp = lsp_next_frag(
2017 LSP_FRAGMENT(lsp->lsp_header->lsp_id) + 1, lsp0,
2018 area, level);
2019 }
2020
2021 struct tlv_mt_neighbors *mt_neighs;
2022 for (ALL_LIST_ELEMENTS_RO(tlv_data.mt_is_neighs, node, mt_neighs)) {
2023 while (mt_neighs->list && listcount(mt_neighs->list)) {
2024 struct tlv_mt_neighbors *frag_mt_neighs;
2025
2026 frag_mt_neighs = tlvs_get_mt_neighbors(&lsp->tlv_data,
2027 mt_neighs->mtid);
2028 _lsp_tlv_fit(lsp, &mt_neighs->list,
2029 &frag_mt_neighs->list,
2030 area->lsp_frag_threshold,
2031 tlv_add_te_is_neighs, &mt_neighs->mtid);
2032 if (mt_neighs->list && listcount(mt_neighs->list))
2033 lsp = lsp_next_frag(
2034 LSP_FRAGMENT(lsp->lsp_header->lsp_id)
2035 + 1,
2036 lsp0, area, level);
2037 }
2038 }
2039
2040
2041 lsp->lsp_header->pdu_len = htons(stream_get_endp(lsp->pdu));
2042
2043 free_tlvs(&tlv_data);
2044
2045 /* Validate the LSP */
2046 retval = parse_tlvs(area->area_tag,
2047 STREAM_DATA(lsp->pdu) + ISIS_FIXED_HDR_LEN
2048 + ISIS_LSP_HDR_LEN,
2049 stream_get_endp(lsp->pdu) - ISIS_FIXED_HDR_LEN
2050 - ISIS_LSP_HDR_LEN,
2051 &expected, &found, &tlv_data, NULL);
2052 assert(retval == ISIS_OK);
2053
2054 return;
2055 }
2056
2057 /*
2058 * 7.3.7 and 7.3.9 Generation on non-pseudonode LSPs
2059 */
2060 int lsp_generate(struct isis_area *area, int level)
2061 {
2062 struct isis_lsp *oldlsp, *newlsp;
2063 u_int32_t seq_num = 0;
2064 u_char lspid[ISIS_SYS_ID_LEN + 2];
2065 u_int16_t rem_lifetime, refresh_time;
2066
2067 if ((area == NULL) || (area->is_type & level) != level)
2068 return ISIS_ERROR;
2069
2070 memset(&lspid, 0, ISIS_SYS_ID_LEN + 2);
2071 memcpy(&lspid, isis->sysid, ISIS_SYS_ID_LEN);
2072
2073 /* only builds the lsp if the area shares the level */
2074 oldlsp = lsp_search(lspid, area->lspdb[level - 1]);
2075 if (oldlsp) {
2076 /* FIXME: we should actually initiate a purge */
2077 seq_num = ntohl(oldlsp->lsp_header->seq_num);
2078 lsp_search_and_destroy(oldlsp->lsp_header->lsp_id,
2079 area->lspdb[level - 1]);
2080 }
2081 rem_lifetime = lsp_rem_lifetime(area, level);
2082 newlsp =
2083 lsp_new(area, lspid, rem_lifetime, seq_num,
2084 area->is_type | area->overload_bit | area->attached_bit,
2085 0, level);
2086 newlsp->area = area;
2087 newlsp->own_lsp = 1;
2088
2089 lsp_insert(newlsp, area->lspdb[level - 1]);
2090 /* build_lsp_data (newlsp, area); */
2091 lsp_build(newlsp, area);
2092 /* time to calculate our checksum */
2093 lsp_seqnum_update(newlsp);
2094 newlsp->last_generated = time(NULL);
2095 lsp_set_all_srmflags(newlsp);
2096
2097 refresh_time = lsp_refresh_time(newlsp, rem_lifetime);
2098
2099 THREAD_TIMER_OFF(area->t_lsp_refresh[level - 1]);
2100 area->lsp_regenerate_pending[level - 1] = 0;
2101 if (level == IS_LEVEL_1)
2102 thread_add_timer(master, lsp_l1_refresh, area, refresh_time,
2103 &area->t_lsp_refresh[level - 1]);
2104 else if (level == IS_LEVEL_2)
2105 thread_add_timer(master, lsp_l2_refresh, area, refresh_time,
2106 &area->t_lsp_refresh[level - 1]);
2107
2108 if (isis->debugs & DEBUG_UPDATE_PACKETS) {
2109 zlog_debug(
2110 "ISIS-Upd (%s): Building L%d LSP %s, len %d, "
2111 "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us",
2112 area->area_tag, level,
2113 rawlspid_print(newlsp->lsp_header->lsp_id),
2114 ntohl(newlsp->lsp_header->pdu_len),
2115 ntohl(newlsp->lsp_header->seq_num),
2116 ntohs(newlsp->lsp_header->checksum),
2117 ntohs(newlsp->lsp_header->rem_lifetime), refresh_time);
2118 }
2119 sched_debug(
2120 "ISIS (%s): Built L%d LSP. Set triggered regenerate to non-pending.",
2121 area->area_tag, level);
2122
2123 return ISIS_OK;
2124 }
2125
2126 /*
2127 * Search own LSPs, update holding time and set SRM
2128 */
2129 static int lsp_regenerate(struct isis_area *area, int level)
2130 {
2131 dict_t *lspdb;
2132 struct isis_lsp *lsp, *frag;
2133 struct listnode *node;
2134 u_char lspid[ISIS_SYS_ID_LEN + 2];
2135 u_int16_t rem_lifetime, refresh_time;
2136
2137 if ((area == NULL) || (area->is_type & level) != level)
2138 return ISIS_ERROR;
2139
2140 lspdb = area->lspdb[level - 1];
2141
2142 memset(lspid, 0, ISIS_SYS_ID_LEN + 2);
2143 memcpy(lspid, isis->sysid, ISIS_SYS_ID_LEN);
2144
2145 lsp = lsp_search(lspid, lspdb);
2146
2147 if (!lsp) {
2148 zlog_err("ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!",
2149 area->area_tag, level);
2150 return ISIS_ERROR;
2151 }
2152
2153 lsp_clear_data(lsp);
2154 lsp_build(lsp, area);
2155 lsp->lsp_header->lsp_bits = lsp_bits_generate(level, area->overload_bit,
2156 area->attached_bit);
2157 rem_lifetime = lsp_rem_lifetime(area, level);
2158 lsp->lsp_header->rem_lifetime = htons(rem_lifetime);
2159 lsp_seqnum_update(lsp);
2160
2161 lsp->last_generated = time(NULL);
2162 lsp_set_all_srmflags(lsp);
2163 for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) {
2164 frag->lsp_header->lsp_bits = lsp_bits_generate(
2165 level, area->overload_bit, area->attached_bit);
2166 /* Set the lifetime values of all the fragments to the same
2167 * value,
2168 * so that no fragment expires before the lsp is refreshed.
2169 */
2170 frag->lsp_header->rem_lifetime = htons(rem_lifetime);
2171 lsp_set_all_srmflags(frag);
2172 }
2173
2174 refresh_time = lsp_refresh_time(lsp, rem_lifetime);
2175 if (level == IS_LEVEL_1)
2176 thread_add_timer(master, lsp_l1_refresh, area, refresh_time,
2177 &area->t_lsp_refresh[level - 1]);
2178 else if (level == IS_LEVEL_2)
2179 thread_add_timer(master, lsp_l2_refresh, area, refresh_time,
2180 &area->t_lsp_refresh[level - 1]);
2181 area->lsp_regenerate_pending[level - 1] = 0;
2182
2183 if (isis->debugs & DEBUG_UPDATE_PACKETS) {
2184 zlog_debug(
2185 "ISIS-Upd (%s): Refreshing our L%d LSP %s, len %d, "
2186 "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us",
2187 area->area_tag, level,
2188 rawlspid_print(lsp->lsp_header->lsp_id),
2189 ntohl(lsp->lsp_header->pdu_len),
2190 ntohl(lsp->lsp_header->seq_num),
2191 ntohs(lsp->lsp_header->checksum),
2192 ntohs(lsp->lsp_header->rem_lifetime), refresh_time);
2193 }
2194 sched_debug(
2195 "ISIS (%s): Rebuilt L%d LSP. Set triggered regenerate to non-pending.",
2196 area->area_tag, level);
2197
2198 return ISIS_OK;
2199 }
2200
2201 /*
2202 * Something has changed or periodic refresh -> regenerate LSP
2203 */
2204 static int lsp_l1_refresh(struct thread *thread)
2205 {
2206 struct isis_area *area;
2207
2208 area = THREAD_ARG(thread);
2209 assert(area);
2210
2211 area->t_lsp_refresh[0] = NULL;
2212 area->lsp_regenerate_pending[0] = 0;
2213
2214 if ((area->is_type & IS_LEVEL_1) == 0)
2215 return ISIS_ERROR;
2216
2217 sched_debug(
2218 "ISIS (%s): LSP L1 refresh timer expired. Refreshing LSP...",
2219 area->area_tag);
2220 return lsp_regenerate(area, IS_LEVEL_1);
2221 }
2222
2223 static int lsp_l2_refresh(struct thread *thread)
2224 {
2225 struct isis_area *area;
2226
2227 area = THREAD_ARG(thread);
2228 assert(area);
2229
2230 area->t_lsp_refresh[1] = NULL;
2231 area->lsp_regenerate_pending[1] = 0;
2232
2233 if ((area->is_type & IS_LEVEL_2) == 0)
2234 return ISIS_ERROR;
2235
2236 sched_debug(
2237 "ISIS (%s): LSP L2 refresh timer expired. Refreshing LSP...",
2238 area->area_tag);
2239 return lsp_regenerate(area, IS_LEVEL_2);
2240 }
2241
2242 int lsp_regenerate_schedule(struct isis_area *area, int level, int all_pseudo)
2243 {
2244 struct isis_lsp *lsp;
2245 u_char id[ISIS_SYS_ID_LEN + 2];
2246 time_t now, diff;
2247 long timeout;
2248 struct listnode *cnode;
2249 struct isis_circuit *circuit;
2250 int lvl;
2251
2252 if (area == NULL)
2253 return ISIS_ERROR;
2254
2255 sched_debug(
2256 "ISIS (%s): Scheduling regeneration of %s LSPs, %sincluding PSNs",
2257 area->area_tag, circuit_t2string(level),
2258 all_pseudo ? "" : "not ");
2259
2260 memcpy(id, isis->sysid, ISIS_SYS_ID_LEN);
2261 LSP_PSEUDO_ID(id) = LSP_FRAGMENT(id) = 0;
2262 now = time(NULL);
2263
2264 for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) {
2265 if (!((level & lvl) && (area->is_type & lvl)))
2266 continue;
2267
2268 sched_debug(
2269 "ISIS (%s): Checking whether L%d needs to be scheduled",
2270 area->area_tag, lvl);
2271
2272 if (area->lsp_regenerate_pending[lvl - 1]) {
2273 struct timeval remain = thread_timer_remain(
2274 area->t_lsp_refresh[lvl - 1]);
2275 sched_debug(
2276 "ISIS (%s): Regeneration is already pending, nothing todo."
2277 " (Due in %lld.%03lld seconds)",
2278 area->area_tag, (long long)remain.tv_sec,
2279 (long long)remain.tv_usec / 1000);
2280 continue;
2281 }
2282
2283 lsp = lsp_search(id, area->lspdb[lvl - 1]);
2284 if (!lsp) {
2285 sched_debug(
2286 "ISIS (%s): We do not have any LSPs to regenerate, nothing todo.",
2287 area->area_tag);
2288 continue;
2289 }
2290
2291 /*
2292 * Throttle avoidance
2293 */
2294 sched_debug(
2295 "ISIS (%s): Will schedule regen timer. Last run was: %lld, Now is: %lld",
2296 area->area_tag, (long long)lsp->last_generated,
2297 (long long)now);
2298 THREAD_TIMER_OFF(area->t_lsp_refresh[lvl - 1]);
2299 diff = now - lsp->last_generated;
2300 if (diff < area->lsp_gen_interval[lvl - 1]) {
2301 timeout =
2302 1000 * (area->lsp_gen_interval[lvl - 1] - diff);
2303 sched_debug(
2304 "ISIS (%s): Scheduling in %ld ms to match configured lsp_gen_interval",
2305 area->area_tag, timeout);
2306 } else {
2307 /*
2308 * lsps are not regenerated if lsp_regenerate function
2309 * is called
2310 * directly. However if the lsp_regenerate call is
2311 * queued for
2312 * later execution it works.
2313 */
2314 timeout = 100;
2315 sched_debug(
2316 "ISIS (%s): Last generation was more than lsp_gen_interval ago."
2317 " Scheduling for execution in %ld ms.",
2318 area->area_tag, timeout);
2319 }
2320
2321 area->lsp_regenerate_pending[lvl - 1] = 1;
2322 if (lvl == IS_LEVEL_1) {
2323 thread_add_timer_msec(master, lsp_l1_refresh, area,
2324 timeout,
2325 &area->t_lsp_refresh[lvl - 1]);
2326 } else if (lvl == IS_LEVEL_2) {
2327 thread_add_timer_msec(master, lsp_l2_refresh, area,
2328 timeout,
2329 &area->t_lsp_refresh[lvl - 1]);
2330 }
2331 }
2332
2333 if (all_pseudo) {
2334 for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit))
2335 lsp_regenerate_schedule_pseudo(circuit, level);
2336 }
2337
2338 return ISIS_OK;
2339 }
2340
2341 /*
2342 * Funcs for pseudonode LSPs
2343 */
2344
2345 /*
2346 * 7.3.8 and 7.3.10 Generation of level 1 and 2 pseudonode LSPs
2347 */
2348 static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit,
2349 int level)
2350 {
2351 struct isis_adjacency *adj;
2352 struct is_neigh *is_neigh;
2353 struct te_is_neigh *te_is_neigh;
2354 struct es_neigh *es_neigh;
2355 struct list *adj_list;
2356 struct listnode *node;
2357 struct isis_area *area = circuit->area;
2358
2359 lsp_debug(
2360 "ISIS (%s): Constructing pseudo LSP %s for interface %s level %d",
2361 area->area_tag, rawlspid_print(lsp->lsp_header->lsp_id),
2362 circuit->interface->name, level);
2363
2364 lsp->level = level;
2365 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
2366 lsp->lsp_header->lsp_bits =
2367 lsp_bits_generate(level, 0, circuit->area->attached_bit);
2368
2369 /*
2370 * add self to IS neighbours
2371 */
2372 if (circuit->area->oldmetric) {
2373 if (lsp->tlv_data.is_neighs == NULL) {
2374 lsp->tlv_data.is_neighs = list_new();
2375 lsp->tlv_data.is_neighs->del = free_tlv;
2376 }
2377 is_neigh = XCALLOC(MTYPE_ISIS_TLV, sizeof(struct is_neigh));
2378
2379 memcpy(&is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN);
2380 listnode_add(lsp->tlv_data.is_neighs, is_neigh);
2381 lsp_debug(
2382 "ISIS (%s): Adding %s.%02x as old-style neighbor (self)",
2383 area->area_tag, sysid_print(is_neigh->neigh_id),
2384 LSP_PSEUDO_ID(is_neigh->neigh_id));
2385 }
2386 if (circuit->area->newmetric) {
2387 if (lsp->tlv_data.te_is_neighs == NULL) {
2388 lsp->tlv_data.te_is_neighs = list_new();
2389 lsp->tlv_data.te_is_neighs->del = free_tlv;
2390 }
2391 te_is_neigh =
2392 XCALLOC(MTYPE_ISIS_TLV, sizeof(struct te_is_neigh));
2393
2394 memcpy(&te_is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN);
2395 listnode_add(lsp->tlv_data.te_is_neighs, te_is_neigh);
2396 lsp_debug(
2397 "ISIS (%s): Adding %s.%02x as te-style neighbor (self)",
2398 area->area_tag, sysid_print(te_is_neigh->neigh_id),
2399 LSP_PSEUDO_ID(te_is_neigh->neigh_id));
2400 }
2401
2402 adj_list = list_new();
2403 isis_adj_build_up_list(circuit->u.bc.adjdb[level - 1], adj_list);
2404
2405 for (ALL_LIST_ELEMENTS_RO(adj_list, node, adj)) {
2406 if (adj->level & level) {
2407 if ((level == IS_LEVEL_1
2408 && adj->sys_type == ISIS_SYSTYPE_L1_IS)
2409 || (level == IS_LEVEL_1
2410 && adj->sys_type == ISIS_SYSTYPE_L2_IS
2411 && adj->adj_usage == ISIS_ADJ_LEVEL1AND2)
2412 || (level == IS_LEVEL_2
2413 && adj->sys_type == ISIS_SYSTYPE_L2_IS)) {
2414 /* an IS neighbour -> add it */
2415 if (circuit->area->oldmetric) {
2416 is_neigh = XCALLOC(
2417 MTYPE_ISIS_TLV,
2418 sizeof(struct is_neigh));
2419
2420 memcpy(&is_neigh->neigh_id, adj->sysid,
2421 ISIS_SYS_ID_LEN);
2422 listnode_add(lsp->tlv_data.is_neighs,
2423 is_neigh);
2424 lsp_debug(
2425 "ISIS (%s): Adding %s.%02x as old-style neighbor (peer)",
2426 area->area_tag,
2427 sysid_print(is_neigh->neigh_id),
2428 LSP_PSEUDO_ID(
2429 is_neigh->neigh_id));
2430 }
2431 if (circuit->area->newmetric) {
2432 te_is_neigh = XCALLOC(
2433 MTYPE_ISIS_TLV,
2434 sizeof(struct te_is_neigh));
2435 memcpy(&te_is_neigh->neigh_id,
2436 adj->sysid, ISIS_SYS_ID_LEN);
2437 listnode_add(lsp->tlv_data.te_is_neighs,
2438 te_is_neigh);
2439 lsp_debug(
2440 "ISIS (%s): Adding %s.%02x as te-style neighbor (peer)",
2441 area->area_tag,
2442 sysid_print(
2443 te_is_neigh->neigh_id),
2444 LSP_PSEUDO_ID(
2445 te_is_neigh->neigh_id));
2446 }
2447 } else if (level == IS_LEVEL_1
2448 && adj->sys_type == ISIS_SYSTYPE_ES) {
2449 /* an ES neigbour add it, if we are building
2450 * level 1 LSP */
2451 /* FIXME: the tlv-format is hard to use here */
2452 if (lsp->tlv_data.es_neighs == NULL) {
2453 lsp->tlv_data.es_neighs = list_new();
2454 lsp->tlv_data.es_neighs->del = free_tlv;
2455 }
2456 es_neigh = XCALLOC(MTYPE_ISIS_TLV,
2457 sizeof(struct es_neigh));
2458
2459 memcpy(&es_neigh->first_es_neigh, adj->sysid,
2460 ISIS_SYS_ID_LEN);
2461 listnode_add(lsp->tlv_data.es_neighs, es_neigh);
2462 lsp_debug(
2463 "ISIS (%s): Adding %s as ES neighbor (peer)",
2464 area->area_tag,
2465 sysid_print(es_neigh->first_es_neigh));
2466 } else {
2467 lsp_debug(
2468 "ISIS (%s): Ignoring neighbor %s, level does not match",
2469 area->area_tag,
2470 sysid_print(adj->sysid));
2471 }
2472 } else {
2473 lsp_debug(
2474 "ISIS (%s): Ignoring neighbor %s, level does not intersect",
2475 area->area_tag, sysid_print(adj->sysid));
2476 }
2477 }
2478 list_delete(adj_list);
2479
2480 lsp_debug("ISIS (%s): Pseudo LSP construction is complete.",
2481 area->area_tag);
2482
2483 /* Reset endp of stream to overwrite only TLV part of it. */
2484 stream_reset(lsp->pdu);
2485 stream_forward_endp(lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
2486
2487 /*
2488 * Add the authentication info if it's present
2489 */
2490 lsp_auth_add(lsp);
2491
2492 if (lsp->tlv_data.is_neighs && listcount(lsp->tlv_data.is_neighs) > 0)
2493 tlv_add_is_neighs(lsp->tlv_data.is_neighs, lsp->pdu);
2494
2495 if (lsp->tlv_data.te_is_neighs
2496 && listcount(lsp->tlv_data.te_is_neighs) > 0)
2497 tlv_add_te_is_neighs(lsp->tlv_data.te_is_neighs, lsp->pdu,
2498 NULL);
2499
2500 if (lsp->tlv_data.es_neighs && listcount(lsp->tlv_data.es_neighs) > 0)
2501 tlv_add_is_neighs(lsp->tlv_data.es_neighs, lsp->pdu);
2502
2503 lsp->lsp_header->pdu_len = htons(stream_get_endp(lsp->pdu));
2504
2505 /* Recompute authentication and checksum information */
2506 lsp_auth_update(lsp);
2507 fletcher_checksum(STREAM_DATA(lsp->pdu) + 12,
2508 ntohs(lsp->lsp_header->pdu_len) - 12, 12);
2509
2510 return;
2511 }
2512
2513 int lsp_generate_pseudo(struct isis_circuit *circuit, int level)
2514 {
2515 dict_t *lspdb = circuit->area->lspdb[level - 1];
2516 struct isis_lsp *lsp;
2517 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
2518 u_int16_t rem_lifetime, refresh_time;
2519
2520 if ((circuit->is_type & level) != level
2521 || (circuit->state != C_STATE_UP)
2522 || (circuit->circ_type != CIRCUIT_T_BROADCAST)
2523 || (circuit->u.bc.is_dr[level - 1] == 0))
2524 return ISIS_ERROR;
2525
2526 memcpy(lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
2527 LSP_FRAGMENT(lsp_id) = 0;
2528 LSP_PSEUDO_ID(lsp_id) = circuit->circuit_id;
2529
2530 /*
2531 * If for some reason have a pseudo LSP in the db already -> regenerate
2532 */
2533 if (lsp_search(lsp_id, lspdb))
2534 return lsp_regenerate_schedule_pseudo(circuit, level);
2535
2536 rem_lifetime = lsp_rem_lifetime(circuit->area, level);
2537 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
2538 lsp = lsp_new(circuit->area, lsp_id, rem_lifetime, 1,
2539 circuit->area->is_type | circuit->area->attached_bit, 0,
2540 level);
2541 lsp->area = circuit->area;
2542
2543 lsp_build_pseudo(lsp, circuit, level);
2544
2545 lsp->own_lsp = 1;
2546 lsp_insert(lsp, lspdb);
2547 lsp_set_all_srmflags(lsp);
2548
2549 refresh_time = lsp_refresh_time(lsp, rem_lifetime);
2550 THREAD_TIMER_OFF(circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
2551 circuit->lsp_regenerate_pending[level - 1] = 0;
2552 if (level == IS_LEVEL_1)
2553 thread_add_timer(
2554 master, lsp_l1_refresh_pseudo, circuit, refresh_time,
2555 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
2556 else if (level == IS_LEVEL_2)
2557 thread_add_timer(
2558 master, lsp_l2_refresh_pseudo, circuit, refresh_time,
2559 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
2560
2561 if (isis->debugs & DEBUG_UPDATE_PACKETS) {
2562 zlog_debug(
2563 "ISIS-Upd (%s): Building L%d Pseudo LSP %s, len %d, "
2564 "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us",
2565 circuit->area->area_tag, level,
2566 rawlspid_print(lsp->lsp_header->lsp_id),
2567 ntohl(lsp->lsp_header->pdu_len),
2568 ntohl(lsp->lsp_header->seq_num),
2569 ntohs(lsp->lsp_header->checksum),
2570 ntohs(lsp->lsp_header->rem_lifetime), refresh_time);
2571 }
2572
2573 return ISIS_OK;
2574 }
2575
2576 static int lsp_regenerate_pseudo(struct isis_circuit *circuit, int level)
2577 {
2578 dict_t *lspdb = circuit->area->lspdb[level - 1];
2579 struct isis_lsp *lsp;
2580 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
2581 u_int16_t rem_lifetime, refresh_time;
2582
2583 if ((circuit->is_type & level) != level
2584 || (circuit->state != C_STATE_UP)
2585 || (circuit->circ_type != CIRCUIT_T_BROADCAST)
2586 || (circuit->u.bc.is_dr[level - 1] == 0))
2587 return ISIS_ERROR;
2588
2589 memcpy(lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
2590 LSP_PSEUDO_ID(lsp_id) = circuit->circuit_id;
2591 LSP_FRAGMENT(lsp_id) = 0;
2592
2593 lsp = lsp_search(lsp_id, lspdb);
2594
2595 if (!lsp) {
2596 zlog_err("lsp_regenerate_pseudo: no l%d LSP %s found!", level,
2597 rawlspid_print(lsp_id));
2598 return ISIS_ERROR;
2599 }
2600 lsp_clear_data(lsp);
2601
2602 lsp_build_pseudo(lsp, circuit, level);
2603
2604 /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
2605 lsp->lsp_header->lsp_bits =
2606 lsp_bits_generate(level, 0, circuit->area->attached_bit);
2607 rem_lifetime = lsp_rem_lifetime(circuit->area, level);
2608 lsp->lsp_header->rem_lifetime = htons(rem_lifetime);
2609 lsp_inc_seqnum(lsp, 0);
2610 lsp->last_generated = time(NULL);
2611 lsp_set_all_srmflags(lsp);
2612
2613 refresh_time = lsp_refresh_time(lsp, rem_lifetime);
2614 if (level == IS_LEVEL_1)
2615 thread_add_timer(
2616 master, lsp_l1_refresh_pseudo, circuit, refresh_time,
2617 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
2618 else if (level == IS_LEVEL_2)
2619 thread_add_timer(
2620 master, lsp_l2_refresh_pseudo, circuit, refresh_time,
2621 &circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
2622
2623 if (isis->debugs & DEBUG_UPDATE_PACKETS) {
2624 zlog_debug(
2625 "ISIS-Upd (%s): Refreshing L%d Pseudo LSP %s, len %d, "
2626 "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us",
2627 circuit->area->area_tag, level,
2628 rawlspid_print(lsp->lsp_header->lsp_id),
2629 ntohl(lsp->lsp_header->pdu_len),
2630 ntohl(lsp->lsp_header->seq_num),
2631 ntohs(lsp->lsp_header->checksum),
2632 ntohs(lsp->lsp_header->rem_lifetime), refresh_time);
2633 }
2634
2635 return ISIS_OK;
2636 }
2637
2638 /*
2639 * Something has changed or periodic refresh -> regenerate pseudo LSP
2640 */
2641 static int lsp_l1_refresh_pseudo(struct thread *thread)
2642 {
2643 struct isis_circuit *circuit;
2644 u_char id[ISIS_SYS_ID_LEN + 2];
2645
2646 circuit = THREAD_ARG(thread);
2647
2648 circuit->u.bc.t_refresh_pseudo_lsp[0] = NULL;
2649 circuit->lsp_regenerate_pending[0] = 0;
2650
2651 if ((circuit->u.bc.is_dr[0] == 0)
2652 || (circuit->is_type & IS_LEVEL_1) == 0) {
2653 memcpy(id, isis->sysid, ISIS_SYS_ID_LEN);
2654 LSP_PSEUDO_ID(id) = circuit->circuit_id;
2655 LSP_FRAGMENT(id) = 0;
2656 lsp_purge_pseudo(id, circuit, IS_LEVEL_1);
2657 return ISIS_ERROR;
2658 }
2659
2660 return lsp_regenerate_pseudo(circuit, IS_LEVEL_1);
2661 }
2662
2663 static int lsp_l2_refresh_pseudo(struct thread *thread)
2664 {
2665 struct isis_circuit *circuit;
2666 u_char id[ISIS_SYS_ID_LEN + 2];
2667
2668 circuit = THREAD_ARG(thread);
2669
2670 circuit->u.bc.t_refresh_pseudo_lsp[1] = NULL;
2671 circuit->lsp_regenerate_pending[1] = 0;
2672
2673 if ((circuit->u.bc.is_dr[1] == 0)
2674 || (circuit->is_type & IS_LEVEL_2) == 0) {
2675 memcpy(id, isis->sysid, ISIS_SYS_ID_LEN);
2676 LSP_PSEUDO_ID(id) = circuit->circuit_id;
2677 LSP_FRAGMENT(id) = 0;
2678 lsp_purge_pseudo(id, circuit, IS_LEVEL_2);
2679 return ISIS_ERROR;
2680 }
2681
2682 return lsp_regenerate_pseudo(circuit, IS_LEVEL_2);
2683 }
2684
2685 int lsp_regenerate_schedule_pseudo(struct isis_circuit *circuit, int level)
2686 {
2687 struct isis_lsp *lsp;
2688 u_char lsp_id[ISIS_SYS_ID_LEN + 2];
2689 time_t now, diff;
2690 long timeout;
2691 int lvl;
2692 struct isis_area *area = circuit->area;
2693
2694 if (circuit->circ_type != CIRCUIT_T_BROADCAST
2695 || circuit->state != C_STATE_UP)
2696 return ISIS_OK;
2697
2698 sched_debug(
2699 "ISIS (%s): Scheduling regeneration of %s pseudo LSP for interface %s",
2700 area->area_tag, circuit_t2string(level),
2701 circuit->interface->name);
2702
2703 memcpy(lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
2704 LSP_PSEUDO_ID(lsp_id) = circuit->circuit_id;
2705 LSP_FRAGMENT(lsp_id) = 0;
2706 now = time(NULL);
2707
2708 for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) {
2709 sched_debug(
2710 "ISIS (%s): Checking whether L%d pseudo LSP needs to be scheduled",
2711 area->area_tag, lvl);
2712
2713 if (!((level & lvl) && (circuit->is_type & lvl))) {
2714 sched_debug("ISIS (%s): Level is not active on circuit",
2715 area->area_tag);
2716 continue;
2717 }
2718
2719 if (circuit->u.bc.is_dr[lvl - 1] == 0) {
2720 sched_debug(
2721 "ISIS (%s): This IS is not DR, nothing to do.",
2722 area->area_tag);
2723 continue;
2724 }
2725
2726 if (circuit->lsp_regenerate_pending[lvl - 1]) {
2727 struct timeval remain = thread_timer_remain(
2728 circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
2729 sched_debug(
2730 "ISIS (%s): Regenerate is already pending, nothing todo."
2731 " (Due in %lld.%03lld seconds)",
2732 area->area_tag, (long long)remain.tv_sec,
2733 (long long)remain.tv_usec / 1000);
2734 continue;
2735 }
2736
2737 lsp = lsp_search(lsp_id, circuit->area->lspdb[lvl - 1]);
2738 if (!lsp) {
2739 sched_debug(
2740 "ISIS (%s): Pseudonode LSP does not exist yet, nothing to regenerate.",
2741 area->area_tag);
2742 continue;
2743 }
2744
2745 /*
2746 * Throttle avoidance
2747 */
2748 sched_debug(
2749 "ISIS (%s): Will schedule PSN regen timer. Last run was: %lld, Now is: %lld",
2750 area->area_tag, (long long)lsp->last_generated,
2751 (long long)now);
2752 THREAD_TIMER_OFF(circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
2753 diff = now - lsp->last_generated;
2754 if (diff < circuit->area->lsp_gen_interval[lvl - 1]) {
2755 timeout =
2756 1000 * (circuit->area->lsp_gen_interval[lvl - 1]
2757 - diff);
2758 sched_debug(
2759 "ISIS (%s): Sechduling in %ld ms to match configured lsp_gen_interval",
2760 area->area_tag, timeout);
2761 } else {
2762 timeout = 100;
2763 sched_debug(
2764 "ISIS (%s): Last generation was more than lsp_gen_interval ago."
2765 " Scheduling for execution in %ld ms.",
2766 area->area_tag, timeout);
2767 }
2768
2769 circuit->lsp_regenerate_pending[lvl - 1] = 1;
2770
2771 if (lvl == IS_LEVEL_1) {
2772 thread_add_timer_msec(
2773 master, lsp_l1_refresh_pseudo, circuit, timeout,
2774 &circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
2775 } else if (lvl == IS_LEVEL_2) {
2776 thread_add_timer_msec(
2777 master, lsp_l2_refresh_pseudo, circuit, timeout,
2778 &circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
2779 }
2780 }
2781
2782 return ISIS_OK;
2783 }
2784
2785 /*
2786 * Walk through LSPs for an area
2787 * - set remaining lifetime
2788 * - set LSPs with SRMflag set for sending
2789 */
2790 int lsp_tick(struct thread *thread)
2791 {
2792 struct isis_area *area;
2793 struct isis_circuit *circuit;
2794 struct isis_lsp *lsp;
2795 struct list *lsp_list;
2796 struct listnode *lspnode, *cnode;
2797 dnode_t *dnode, *dnode_next;
2798 int level;
2799 u_int16_t rem_lifetime;
2800
2801 lsp_list = list_new();
2802
2803 area = THREAD_ARG(thread);
2804 assert(area);
2805 area->t_tick = NULL;
2806 thread_add_timer(master, lsp_tick, area, 1, &area->t_tick);
2807
2808 /*
2809 * Build a list of LSPs with (any) SRMflag set
2810 * and removed the ones that have aged out
2811 */
2812 for (level = 0; level < ISIS_LEVELS; level++) {
2813 if (area->lspdb[level] && dict_count(area->lspdb[level]) > 0) {
2814 for (dnode = dict_first(area->lspdb[level]);
2815 dnode != NULL; dnode = dnode_next) {
2816 dnode_next =
2817 dict_next(area->lspdb[level], dnode);
2818 lsp = dnode_get(dnode);
2819
2820 /*
2821 * The lsp rem_lifetime is kept at 0 for MaxAge
2822 * or
2823 * ZeroAgeLifetime depending on explicit purge
2824 * or
2825 * natural age out. So schedule spf only once
2826 * when
2827 * the first time rem_lifetime becomes 0.
2828 */
2829 rem_lifetime =
2830 ntohs(lsp->lsp_header->rem_lifetime);
2831 lsp_set_time(lsp);
2832
2833 /*
2834 * Schedule may run spf which should be done
2835 * only after
2836 * the lsp rem_lifetime becomes 0 for the first
2837 * time.
2838 * ISO 10589 - 7.3.16.4 first paragraph.
2839 */
2840 if (rem_lifetime == 1
2841 && lsp->lsp_header->seq_num != 0) {
2842 /* 7.3.16.4 a) set SRM flags on all */
2843 lsp_set_all_srmflags(lsp);
2844 /* 7.3.16.4 b) retain only the header
2845 * FIXME */
2846 /* 7.3.16.4 c) record the time to purge
2847 * FIXME */
2848 /* run/schedule spf */
2849 /* isis_spf_schedule is called inside
2850 * lsp_destroy() below;
2851 * so it is not needed here. */
2852 /* isis_spf_schedule (lsp->area,
2853 * lsp->level); */
2854 }
2855
2856 if (lsp->age_out == 0) {
2857 zlog_debug(
2858 "ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out",
2859 area->area_tag, lsp->level,
2860 rawlspid_print(
2861 lsp->lsp_header
2862 ->lsp_id),
2863 ntohl(lsp->lsp_header
2864 ->seq_num));
2865 lsp_destroy(lsp);
2866 lsp = NULL;
2867 dict_delete_free(area->lspdb[level],
2868 dnode);
2869 } else if (flags_any_set(lsp->SRMflags))
2870 listnode_add(lsp_list, lsp);
2871 }
2872
2873 /*
2874 * Send LSPs on circuits indicated by the SRMflags
2875 */
2876 if (listcount(lsp_list) > 0) {
2877 for (ALL_LIST_ELEMENTS_RO(area->circuit_list,
2878 cnode, circuit)) {
2879 int diff =
2880 time(NULL)
2881 - circuit->lsp_queue_last_cleared;
2882 if (circuit->lsp_queue == NULL
2883 || diff < MIN_LSP_TRANS_INTERVAL)
2884 continue;
2885 for (ALL_LIST_ELEMENTS_RO(
2886 lsp_list, lspnode, lsp)) {
2887 if (circuit->upadjcount
2888 [lsp->level - 1]
2889 && ISIS_CHECK_FLAG(
2890 lsp->SRMflags,
2891 circuit)) {
2892 /* Add the lsp only if
2893 * it is not already in
2894 * lsp
2895 * queue */
2896 if (!listnode_lookup(
2897 circuit->lsp_queue,
2898 lsp)) {
2899 listnode_add(
2900 circuit->lsp_queue,
2901 lsp);
2902 thread_add_event(
2903 master,
2904 send_lsp,
2905 circuit,
2906 0,
2907 NULL);
2908 }
2909 }
2910 }
2911 }
2912 list_delete_all_node(lsp_list);
2913 }
2914 }
2915 }
2916
2917 list_delete(lsp_list);
2918
2919 return ISIS_OK;
2920 }
2921
2922 void lsp_purge_pseudo(u_char *id, struct isis_circuit *circuit, int level)
2923 {
2924 struct isis_lsp *lsp;
2925 u_int16_t seq_num;
2926 u_int8_t lsp_bits;
2927
2928 lsp = lsp_search(id, circuit->area->lspdb[level - 1]);
2929 if (!lsp)
2930 return;
2931
2932 /* store old values */
2933 seq_num = lsp->lsp_header->seq_num;
2934 lsp_bits = lsp->lsp_header->lsp_bits;
2935
2936 /* reset stream */
2937 lsp_clear_data(lsp);
2938 stream_reset(lsp->pdu);
2939
2940 /* update header */
2941 lsp->lsp_header->pdu_len = htons(ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
2942 memcpy(lsp->lsp_header->lsp_id, id, ISIS_SYS_ID_LEN + 2);
2943 lsp->lsp_header->checksum = 0;
2944 lsp->lsp_header->seq_num = seq_num;
2945 lsp->lsp_header->rem_lifetime = 0;
2946 lsp->lsp_header->lsp_bits = lsp_bits;
2947 lsp->level = level;
2948 lsp->age_out = lsp->area->max_lsp_lifetime[level - 1];
2949 stream_forward_endp(lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
2950
2951 /*
2952 * Add and update the authentication info if its present
2953 */
2954 lsp_auth_add(lsp);
2955 lsp->lsp_header->pdu_len = htons(stream_get_endp(lsp->pdu));
2956 lsp_auth_update(lsp);
2957 fletcher_checksum(STREAM_DATA(lsp->pdu) + 12,
2958 ntohs(lsp->lsp_header->pdu_len) - 12, 12);
2959
2960 lsp_set_all_srmflags(lsp);
2961
2962 return;
2963 }
2964
2965 /*
2966 * Purge own LSP that is received and we don't have.
2967 * -> Do as in 7.3.16.4
2968 */
2969 void lsp_purge_non_exist(int level, struct isis_link_state_hdr *lsp_hdr,
2970 struct isis_area *area)
2971 {
2972 struct isis_lsp *lsp;
2973 uint8_t pdu_type =
2974 (level == IS_LEVEL_1) ? L1_LINK_STATE : L2_LINK_STATE;
2975
2976 /*
2977 * We need to create the LSP to be purged
2978 */
2979 lsp = XCALLOC(MTYPE_ISIS_LSP, sizeof(struct isis_lsp));
2980 lsp->area = area;
2981 lsp->level = level;
2982 lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu);
2983 fill_fixed_hdr(pdu_type, lsp->pdu);
2984
2985 lsp->lsp_header = (struct isis_link_state_hdr *)(STREAM_DATA(lsp->pdu)
2986 + ISIS_FIXED_HDR_LEN);
2987 memcpy(lsp->lsp_header, lsp_hdr, ISIS_LSP_HDR_LEN);
2988 stream_forward_endp(lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
2989
2990 /*
2991 * Set the remaining lifetime to 0
2992 */
2993 lsp->lsp_header->rem_lifetime = 0;
2994
2995 /*
2996 * Add and update the authentication info if its present
2997 */
2998 lsp_auth_add(lsp);
2999 lsp_auth_update(lsp);
3000
3001 /*
3002 * Update the PDU length to header plus any authentication TLV.
3003 */
3004 lsp->lsp_header->pdu_len = htons(stream_get_endp(lsp->pdu));
3005
3006 /*
3007 * Put the lsp into LSPdb
3008 */
3009 lsp_insert(lsp, area->lspdb[lsp->level - 1]);
3010
3011 /*
3012 * Send in to whole area
3013 */
3014 lsp_set_all_srmflags(lsp);
3015
3016 return;
3017 }
3018
3019 void lsp_set_all_srmflags(struct isis_lsp *lsp)
3020 {
3021 struct listnode *node;
3022 struct isis_circuit *circuit;
3023
3024 assert(lsp);
3025
3026 ISIS_FLAGS_CLEAR_ALL(lsp->SRMflags);
3027
3028 if (lsp->area) {
3029 struct list *circuit_list = lsp->area->circuit_list;
3030 for (ALL_LIST_ELEMENTS_RO(circuit_list, node, circuit)) {
3031 ISIS_SET_FLAG(lsp->SRMflags, circuit);
3032 }
3033 }
3034 }