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