Annotation of embedaddon/quagga/isisd/isis_dr.c, revision 1.1.1.2

1.1       misho       1: /*
                      2:  * IS-IS Rout(e)ing protocol - isis_dr.c
                      3:  *                             IS-IS designated router related routines   
                      4:  *
                      5:  * Copyright (C) 2001,2002   Sampo Saaristo
                      6:  *                           Tampere University of Technology      
                      7:  *                           Institute of Communications Engineering
                      8:  *
                      9:  * This program is free software; you can redistribute it and/or modify it 
                     10:  * under the terms of the GNU General Public Licenseas published by the Free 
                     11:  * Software Foundation; either version 2 of the License, or (at your option) 
                     12:  * any later version.
                     13:  *
                     14:  * This program is distributed in the hope that it will be useful,but WITHOUT 
                     15:  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
                     16:  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
                     17:  * more details.
                     18: 
                     19:  * You should have received a copy of the GNU General Public License along 
                     20:  * with this program; if not, write to the Free Software Foundation, Inc., 
                     21:  * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
                     22:  */
                     23: 
                     24: 
                     25: #include <zebra.h>
                     26: 
                     27: #include "log.h"
                     28: #include "hash.h"
                     29: #include "thread.h"
                     30: #include "linklist.h"
                     31: #include "vty.h"
                     32: #include "stream.h"
                     33: #include "if.h"
                     34: 
                     35: #include "isisd/dict.h"
                     36: #include "isisd/isis_constants.h"
                     37: #include "isisd/isis_common.h"
                     38: #include "isisd/isis_misc.h"
                     39: #include "isisd/isis_flags.h"
                     40: #include "isisd/isis_circuit.h"
                     41: #include "isisd/isisd.h"
                     42: #include "isisd/isis_adjacency.h"
                     43: #include "isisd/isis_constants.h"
                     44: #include "isisd/isis_pdu.h"
                     45: #include "isisd/isis_tlv.h"
                     46: #include "isisd/isis_lsp.h"
                     47: #include "isisd/isis_dr.h"
                     48: #include "isisd/isis_events.h"
                     49: 
                     50: const char *
                     51: isis_disflag2string (int disflag)
                     52: {
                     53: 
                     54:   switch (disflag)
                     55:     {
                     56:     case ISIS_IS_NOT_DIS:
                     57:       return "is not DIS";
                     58:     case ISIS_IS_DIS:
                     59:       return "is DIS";
                     60:     case ISIS_WAS_DIS:
                     61:       return "was DIS";
                     62:     default:
                     63:       return "unknown DIS state";
                     64:     }
                     65:   return NULL;                 /* not reached */
                     66: }
                     67: 
                     68: int
                     69: isis_run_dr_l1 (struct thread *thread)
                     70: {
                     71:   struct isis_circuit *circuit;
                     72: 
                     73:   circuit = THREAD_ARG (thread);
                     74:   assert (circuit);
                     75: 
                     76:   if (circuit->u.bc.run_dr_elect[0])
                     77:     zlog_warn ("isis_run_dr(): run_dr_elect already set for l1");
                     78: 
                     79:   circuit->u.bc.t_run_dr[0] = NULL;
                     80:   circuit->u.bc.run_dr_elect[0] = 1;
                     81: 
                     82:   return ISIS_OK;
                     83: }
                     84: 
                     85: int
                     86: isis_run_dr_l2 (struct thread *thread)
                     87: {
                     88:   struct isis_circuit *circuit;
                     89: 
                     90:   circuit = THREAD_ARG (thread);
                     91:   assert (circuit);
                     92: 
                     93:   if (circuit->u.bc.run_dr_elect[1])
                     94:     zlog_warn ("isis_run_dr(): run_dr_elect already set for l2");
                     95: 
                     96: 
                     97:   circuit->u.bc.t_run_dr[1] = NULL;
                     98:   circuit->u.bc.run_dr_elect[1] = 1;
                     99: 
                    100:   return ISIS_OK;
                    101: }
                    102: 
                    103: static int
                    104: isis_check_dr_change (struct isis_adjacency *adj, int level)
                    105: {
                    106:   int i;
                    107: 
                    108:   if (adj->dis_record[level - 1].dis !=
                    109:       adj->dis_record[(1 * ISIS_LEVELS) + level - 1].dis)
                    110:     /* was there a DIS state transition ? */
                    111:     {
                    112:       adj->dischanges[level - 1]++;
                    113:       /* ok rotate the history list through */
                    114:       for (i = DIS_RECORDS - 1; i > 0; i--)
                    115:        {
                    116:          adj->dis_record[(i * ISIS_LEVELS) + level - 1].dis =
                    117:            adj->dis_record[((i - 1) * ISIS_LEVELS) + level - 1].dis;
                    118:          adj->dis_record[(i * ISIS_LEVELS) + level - 1].last_dis_change =
                    119:            adj->dis_record[((i - 1) * ISIS_LEVELS) + level -
                    120:                            1].last_dis_change;
                    121:        }
                    122:     }
                    123:   return ISIS_OK;
                    124: }
                    125: 
                    126: int
                    127: isis_dr_elect (struct isis_circuit *circuit, int level)
                    128: {
                    129:   struct list *adjdb;
                    130:   struct listnode *node;
                    131:   struct isis_adjacency *adj, *adj_dr = NULL;
                    132:   struct list *list = list_new ();
                    133:   u_char own_prio;
                    134:   int biggest_prio = -1;
                    135:   int cmp_res, retval = ISIS_OK;
                    136: 
1.1.1.2 ! misho     137:   own_prio = circuit->priority[level - 1];
1.1       misho     138:   adjdb = circuit->u.bc.adjdb[level - 1];
                    139: 
                    140:   if (!adjdb)
                    141:     {
                    142:       zlog_warn ("isis_dr_elect() adjdb == NULL");
                    143:       list_delete (list);
1.1.1.2 ! misho     144:       return ISIS_WARNING;
1.1       misho     145:     }
                    146:   isis_adj_build_up_list (adjdb, list);
                    147: 
                    148:   /*
                    149:    * Loop the adjacencies and find the one with the biggest priority
                    150:    */
                    151:   for (ALL_LIST_ELEMENTS_RO (list, node, adj))
                    152:     {
                    153:       /* clear flag for show output */
                    154:       adj->dis_record[level - 1].dis = ISIS_IS_NOT_DIS;
                    155:       adj->dis_record[level - 1].last_dis_change = time (NULL);
                    156: 
                    157:       if (adj->prio[level - 1] > biggest_prio)
                    158:        {
                    159:          biggest_prio = adj->prio[level - 1];
                    160:          adj_dr = adj;
                    161:        }
                    162:       else if (adj->prio[level - 1] == biggest_prio)
                    163:        {
                    164:          /*
                    165:           * Comparison of MACs breaks a tie
                    166:           */
                    167:          if (adj_dr)
                    168:            {
                    169:              cmp_res = memcmp (adj_dr->snpa, adj->snpa, ETH_ALEN);
                    170:              if (cmp_res < 0)
                    171:                {
                    172:                  adj_dr = adj;
                    173:                }
                    174:              if (cmp_res == 0)
                    175:                zlog_warn
                    176:                  ("isis_dr_elect(): multiple adjacencies with same SNPA");
                    177:            }
                    178:          else
                    179:            {
                    180:              adj_dr = adj;
                    181:            }
                    182:        }
                    183:     }
                    184: 
                    185:   if (!adj_dr)
                    186:     {
                    187:       /*
1.1.1.2 ! misho     188:        * Could not find the DR - means we are alone. Resign if we were DR.
1.1       misho     189:        */
1.1.1.2 ! misho     190:       if (circuit->u.bc.is_dr[level - 1])
        !           191:         retval = isis_dr_resign (circuit, level);
        !           192:       list_delete (list);
        !           193:       return retval;
1.1       misho     194:     }
                    195: 
                    196:   /*
                    197:    * Now we have the DR adjacency, compare it to self
                    198:    */
1.1.1.2 ! misho     199:   if (adj_dr->prio[level - 1] < own_prio ||
        !           200:       (adj_dr->prio[level - 1] == own_prio &&
        !           201:        memcmp (adj_dr->snpa, circuit->u.bc.snpa, ETH_ALEN) < 0))
1.1       misho     202:     {
1.1.1.2 ! misho     203:       adj_dr->dis_record[level - 1].dis = ISIS_IS_NOT_DIS;
        !           204:       adj_dr->dis_record[level - 1].last_dis_change = time (NULL);
1.1       misho     205: 
1.1.1.2 ! misho     206:       /* rotate the history log */
        !           207:       for (ALL_LIST_ELEMENTS_RO (list, node, adj))
        !           208:         isis_check_dr_change (adj, level);
        !           209: 
        !           210:       /* We are the DR, commence DR */
        !           211:       if (circuit->u.bc.is_dr[level - 1] == 0 && listcount (list) > 0)
        !           212:         retval = isis_dr_commence (circuit, level);
1.1       misho     213:     }
                    214:   else
                    215:     {
                    216:       /* ok we have found the DIS - lets mark the adjacency */
                    217:       /* set flag for show output */
                    218:       adj_dr->dis_record[level - 1].dis = ISIS_IS_DIS;
                    219:       adj_dr->dis_record[level - 1].last_dis_change = time (NULL);
                    220: 
                    221:       /* now loop through a second time to check if there has been a DIS change
                    222:        * if yes rotate the history log
                    223:        */
                    224: 
                    225:       for (ALL_LIST_ELEMENTS_RO (list, node, adj))
                    226:         isis_check_dr_change (adj, level);
                    227: 
                    228:       /*
                    229:        * We are not DR - if we were -> resign
                    230:        */
                    231:       if (circuit->u.bc.is_dr[level - 1])
1.1.1.2 ! misho     232:         retval = isis_dr_resign (circuit, level);
1.1       misho     233:     }
1.1.1.2 ! misho     234:   list_delete (list);
1.1       misho     235:   return retval;
                    236: }
                    237: 
                    238: int
                    239: isis_dr_resign (struct isis_circuit *circuit, int level)
                    240: {
                    241:   u_char id[ISIS_SYS_ID_LEN + 2];
                    242: 
                    243:   zlog_debug ("isis_dr_resign l%d", level);
                    244: 
                    245:   circuit->u.bc.is_dr[level - 1] = 0;
                    246:   circuit->u.bc.run_dr_elect[level - 1] = 0;
                    247:   THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[level - 1]);
                    248:   THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
1.1.1.2 ! misho     249:   circuit->lsp_regenerate_pending[level - 1] = 0;
1.1       misho     250: 
                    251:   memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
                    252:   LSP_PSEUDO_ID (id) = circuit->circuit_id;
                    253:   LSP_FRAGMENT (id) = 0;
1.1.1.2 ! misho     254:   lsp_purge_pseudo (id, circuit, level);
1.1       misho     255: 
                    256:   if (level == 1)
                    257:     {
                    258:       memset (circuit->u.bc.l1_desig_is, 0, ISIS_SYS_ID_LEN + 1);
                    259: 
                    260:       THREAD_TIMER_OFF (circuit->t_send_csnp[0]);
                    261: 
                    262:       THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1,
                    263:                       circuit, 2 * circuit->hello_interval[0]);
                    264: 
                    265:       THREAD_TIMER_ON (master, circuit->t_send_psnp[0], send_l1_psnp, circuit,
                    266:                       isis_jitter (circuit->psnp_interval[level - 1],
                    267:                                    PSNP_JITTER));
                    268:     }
                    269:   else
                    270:     {
                    271:       memset (circuit->u.bc.l2_desig_is, 0, ISIS_SYS_ID_LEN + 1);
                    272: 
                    273:       THREAD_TIMER_OFF (circuit->t_send_csnp[1]);
                    274: 
                    275:       THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[1], isis_run_dr_l2,
                    276:                       circuit, 2 * circuit->hello_interval[1]);
                    277: 
                    278:       THREAD_TIMER_ON (master, circuit->t_send_psnp[1], send_l2_psnp, circuit,
                    279:                       isis_jitter (circuit->psnp_interval[level - 1],
                    280:                                    PSNP_JITTER));
                    281:     }
                    282: 
                    283:   thread_add_event (master, isis_event_dis_status_change, circuit, 0);
                    284: 
                    285:   return ISIS_OK;
                    286: }
                    287: 
                    288: int
                    289: isis_dr_commence (struct isis_circuit *circuit, int level)
                    290: {
                    291:   u_char old_dr[ISIS_SYS_ID_LEN + 2];
                    292: 
                    293:   if (isis->debugs & DEBUG_EVENTS)
                    294:     zlog_debug ("isis_dr_commence l%d", level);
                    295: 
                    296:   /* Lets keep a pause in DR election */
                    297:   circuit->u.bc.run_dr_elect[level - 1] = 0;
                    298:   if (level == 1)
                    299:     THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1,
                    300:                     circuit, 2 * circuit->hello_interval[0]);
                    301:   else
                    302:     THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[1], isis_run_dr_l2,
                    303:                     circuit, 2 * circuit->hello_interval[1]);
                    304:   circuit->u.bc.is_dr[level - 1] = 1;
                    305: 
                    306:   if (level == 1)
                    307:     {
                    308:       memcpy (old_dr, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
                    309:       LSP_FRAGMENT (old_dr) = 0;
                    310:       if (LSP_PSEUDO_ID (old_dr))
                    311:        {
                    312:          /* there was a dr elected, purge its LSPs from the db */
1.1.1.2 ! misho     313:          lsp_purge_pseudo (old_dr, circuit, level);
1.1       misho     314:        }
                    315:       memcpy (circuit->u.bc.l1_desig_is, isis->sysid, ISIS_SYS_ID_LEN);
                    316:       *(circuit->u.bc.l1_desig_is + ISIS_SYS_ID_LEN) = circuit->circuit_id;
                    317: 
                    318:       assert (circuit->circuit_id);    /* must be non-zero */
                    319:       /*    if (circuit->t_send_l1_psnp)
                    320:          thread_cancel (circuit->t_send_l1_psnp); */
1.1.1.2 ! misho     321:       lsp_generate_pseudo (circuit, 1);
1.1       misho     322: 
                    323:       THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[0]);
                    324:       THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1,
                    325:                       circuit, 2 * circuit->hello_interval[0]);
                    326: 
                    327:       THREAD_TIMER_ON (master, circuit->t_send_csnp[0], send_l1_csnp, circuit,
                    328:                       isis_jitter (circuit->csnp_interval[level - 1],
                    329:                                    CSNP_JITTER));
                    330: 
                    331:     }
                    332:   else
                    333:     {
                    334:       memcpy (old_dr, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
                    335:       LSP_FRAGMENT (old_dr) = 0;
                    336:       if (LSP_PSEUDO_ID (old_dr))
                    337:        {
                    338:          /* there was a dr elected, purge its LSPs from the db */
1.1.1.2 ! misho     339:          lsp_purge_pseudo (old_dr, circuit, level);
1.1       misho     340:        }
                    341:       memcpy (circuit->u.bc.l2_desig_is, isis->sysid, ISIS_SYS_ID_LEN);
                    342:       *(circuit->u.bc.l2_desig_is + ISIS_SYS_ID_LEN) = circuit->circuit_id;
                    343: 
                    344:       assert (circuit->circuit_id);    /* must be non-zero */
                    345:       /*    if (circuit->t_send_l1_psnp)
                    346:          thread_cancel (circuit->t_send_l1_psnp); */
1.1.1.2 ! misho     347:       lsp_generate_pseudo (circuit, 2);
1.1       misho     348: 
                    349:       THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[1]);
                    350:       THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[1], isis_run_dr_l2,
                    351:                       circuit, 2 * circuit->hello_interval[1]);
                    352: 
                    353:       THREAD_TIMER_ON (master, circuit->t_send_csnp[1], send_l2_csnp, circuit,
                    354:                       isis_jitter (circuit->csnp_interval[level - 1],
                    355:                                    CSNP_JITTER));
                    356:     }
                    357: 
                    358:   thread_add_event (master, isis_event_dis_status_change, circuit, 0);
                    359: 
                    360:   return ISIS_OK;
                    361: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>