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>