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