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