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

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: extern struct isis *isis;
                     51: extern struct thread_master *master;
                     52: 
                     53: const char *
                     54: isis_disflag2string (int disflag)
                     55: {
                     56: 
                     57:   switch (disflag)
                     58:     {
                     59:     case ISIS_IS_NOT_DIS:
                     60:       return "is not DIS";
                     61:     case ISIS_IS_DIS:
                     62:       return "is DIS";
                     63:     case ISIS_WAS_DIS:
                     64:       return "was DIS";
                     65:     default:
                     66:       return "unknown DIS state";
                     67:     }
                     68:   return NULL;                 /* not reached */
                     69: }
                     70: 
                     71: int
                     72: isis_run_dr_l1 (struct thread *thread)
                     73: {
                     74:   struct isis_circuit *circuit;
                     75: 
                     76:   circuit = THREAD_ARG (thread);
                     77:   assert (circuit);
                     78: 
                     79:   if (circuit->u.bc.run_dr_elect[0])
                     80:     zlog_warn ("isis_run_dr(): run_dr_elect already set for l1");
                     81: 
                     82:   circuit->u.bc.t_run_dr[0] = NULL;
                     83:   circuit->u.bc.run_dr_elect[0] = 1;
                     84: 
                     85:   return ISIS_OK;
                     86: }
                     87: 
                     88: int
                     89: isis_run_dr_l2 (struct thread *thread)
                     90: {
                     91:   struct isis_circuit *circuit;
                     92: 
                     93:   circuit = THREAD_ARG (thread);
                     94:   assert (circuit);
                     95: 
                     96:   if (circuit->u.bc.run_dr_elect[1])
                     97:     zlog_warn ("isis_run_dr(): run_dr_elect already set for l2");
                     98: 
                     99: 
                    100:   circuit->u.bc.t_run_dr[1] = NULL;
                    101:   circuit->u.bc.run_dr_elect[1] = 1;
                    102: 
                    103:   return ISIS_OK;
                    104: }
                    105: 
                    106: static int
                    107: isis_check_dr_change (struct isis_adjacency *adj, int level)
                    108: {
                    109:   int i;
                    110: 
                    111:   if (adj->dis_record[level - 1].dis !=
                    112:       adj->dis_record[(1 * ISIS_LEVELS) + level - 1].dis)
                    113:     /* was there a DIS state transition ? */
                    114:     {
                    115:       adj->dischanges[level - 1]++;
                    116:       /* ok rotate the history list through */
                    117:       for (i = DIS_RECORDS - 1; i > 0; i--)
                    118:        {
                    119:          adj->dis_record[(i * ISIS_LEVELS) + level - 1].dis =
                    120:            adj->dis_record[((i - 1) * ISIS_LEVELS) + level - 1].dis;
                    121:          adj->dis_record[(i * ISIS_LEVELS) + level - 1].last_dis_change =
                    122:            adj->dis_record[((i - 1) * ISIS_LEVELS) + level -
                    123:                            1].last_dis_change;
                    124:        }
                    125:     }
                    126:   return ISIS_OK;
                    127: }
                    128: 
                    129: int
                    130: isis_dr_elect (struct isis_circuit *circuit, int level)
                    131: {
                    132:   struct list *adjdb;
                    133:   struct listnode *node;
                    134:   struct isis_adjacency *adj, *adj_dr = NULL;
                    135:   struct list *list = list_new ();
                    136:   u_char own_prio;
                    137:   int biggest_prio = -1;
                    138:   int cmp_res, retval = ISIS_OK;
                    139: 
                    140:   own_prio = circuit->u.bc.priority[level - 1];
                    141:   adjdb = circuit->u.bc.adjdb[level - 1];
                    142: 
                    143:   if (!adjdb)
                    144:     {
                    145:       zlog_warn ("isis_dr_elect() adjdb == NULL");
                    146:       retval = ISIS_WARNING;
                    147:       list_delete (list);
                    148:       goto out;
                    149:     }
                    150:   isis_adj_build_up_list (adjdb, list);
                    151: 
                    152:   /*
                    153:    * Loop the adjacencies and find the one with the biggest priority
                    154:    */
                    155:   for (ALL_LIST_ELEMENTS_RO (list, node, adj))
                    156:     {
                    157:       /* clear flag for show output */
                    158:       adj->dis_record[level - 1].dis = ISIS_IS_NOT_DIS;
                    159:       adj->dis_record[level - 1].last_dis_change = time (NULL);
                    160: 
                    161:       if (adj->prio[level - 1] > biggest_prio)
                    162:        {
                    163:          biggest_prio = adj->prio[level - 1];
                    164:          adj_dr = adj;
                    165:        }
                    166:       else if (adj->prio[level - 1] == biggest_prio)
                    167:        {
                    168:          /*
                    169:           * Comparison of MACs breaks a tie
                    170:           */
                    171:          if (adj_dr)
                    172:            {
                    173:              cmp_res = memcmp (adj_dr->snpa, adj->snpa, ETH_ALEN);
                    174:              if (cmp_res < 0)
                    175:                {
                    176:                  adj_dr = adj;
                    177:                }
                    178:              if (cmp_res == 0)
                    179:                zlog_warn
                    180:                  ("isis_dr_elect(): multiple adjacencies with same SNPA");
                    181:            }
                    182:          else
                    183:            {
                    184:              adj_dr = adj;
                    185:            }
                    186:        }
                    187:     }
                    188: 
                    189:   if (!adj_dr)
                    190:     {
                    191:       /*
                    192:        * Could not find the DR - means we are alone and thus the DR
                    193:        */
                    194:       if (!circuit->u.bc.is_dr[level - 1])
                    195:        {
                    196:          list_delete (list);
                    197:          list = NULL;
                    198:          return isis_dr_commence (circuit, level);
                    199:        }
                    200:       goto out;
                    201:     }
                    202: 
                    203:   /*
                    204:    * Now we have the DR adjacency, compare it to self
                    205:    */
                    206:   if (adj_dr->prio[level - 1] < own_prio
                    207:       || (adj_dr->prio[level - 1] == own_prio
                    208:          && memcmp (adj_dr->snpa, circuit->u.bc.snpa, ETH_ALEN) < 0))
                    209:     {
                    210:       if (!circuit->u.bc.is_dr[level - 1])
                    211:        {
                    212:          /*
                    213:           * We are the DR
                    214:           */
                    215: 
                    216:          /* rotate the history log */
                    217:          for (ALL_LIST_ELEMENTS_RO (list, node, adj))
                    218:             isis_check_dr_change (adj, level);
                    219: 
                    220:          /* commence */
                    221:          list_delete (list);
                    222:          return isis_dr_commence (circuit, level);
                    223:        }
                    224:     }
                    225:   else
                    226:     {
                    227: 
                    228:       /* ok we have found the DIS - lets mark the adjacency */
                    229:       /* set flag for show output */
                    230:       adj_dr->dis_record[level - 1].dis = ISIS_IS_DIS;
                    231:       adj_dr->dis_record[level - 1].last_dis_change = time (NULL);
                    232: 
                    233:       /* now loop through a second time to check if there has been a DIS change
                    234:        * if yes rotate the history log
                    235:        */
                    236: 
                    237:       for (ALL_LIST_ELEMENTS_RO (list, node, adj))
                    238:         isis_check_dr_change (adj, level);
                    239: 
                    240:       /*
                    241:        * We are not DR - if we were -> resign
                    242:        */
                    243: 
                    244:       if (circuit->u.bc.is_dr[level - 1])
                    245:        {
                    246:          list_delete (list);
                    247:          return isis_dr_resign (circuit, level);
                    248:        }
                    249:     }
                    250: out:
                    251:   if (list)
                    252:     list_delete (list);
                    253:   return retval;
                    254: }
                    255: 
                    256: int
                    257: isis_dr_resign (struct isis_circuit *circuit, int level)
                    258: {
                    259:   u_char id[ISIS_SYS_ID_LEN + 2];
                    260: 
                    261:   zlog_debug ("isis_dr_resign l%d", level);
                    262: 
                    263:   circuit->u.bc.is_dr[level - 1] = 0;
                    264:   circuit->u.bc.run_dr_elect[level - 1] = 0;
                    265:   THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[level - 1]);
                    266:   THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
                    267: 
                    268:   memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
                    269:   LSP_PSEUDO_ID (id) = circuit->circuit_id;
                    270:   LSP_FRAGMENT (id) = 0;
                    271:   lsp_purge_dr (id, circuit, level);
                    272: 
                    273:   if (level == 1)
                    274:     {
                    275:       memset (circuit->u.bc.l1_desig_is, 0, ISIS_SYS_ID_LEN + 1);
                    276: 
                    277:       THREAD_TIMER_OFF (circuit->t_send_csnp[0]);
                    278: 
                    279:       THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1,
                    280:                       circuit, 2 * circuit->hello_interval[0]);
                    281: 
                    282:       THREAD_TIMER_ON (master, circuit->t_send_psnp[0], send_l1_psnp, circuit,
                    283:                       isis_jitter (circuit->psnp_interval[level - 1],
                    284:                                    PSNP_JITTER));
                    285:     }
                    286:   else
                    287:     {
                    288:       memset (circuit->u.bc.l2_desig_is, 0, ISIS_SYS_ID_LEN + 1);
                    289: 
                    290:       THREAD_TIMER_OFF (circuit->t_send_csnp[1]);
                    291: 
                    292:       THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[1], isis_run_dr_l2,
                    293:                       circuit, 2 * circuit->hello_interval[1]);
                    294: 
                    295:       THREAD_TIMER_ON (master, circuit->t_send_psnp[1], send_l2_psnp, circuit,
                    296:                       isis_jitter (circuit->psnp_interval[level - 1],
                    297:                                    PSNP_JITTER));
                    298:     }
                    299: 
                    300:   thread_add_event (master, isis_event_dis_status_change, circuit, 0);
                    301: 
                    302:   return ISIS_OK;
                    303: }
                    304: 
                    305: int
                    306: isis_dr_commence (struct isis_circuit *circuit, int level)
                    307: {
                    308:   u_char old_dr[ISIS_SYS_ID_LEN + 2];
                    309: 
                    310:   if (isis->debugs & DEBUG_EVENTS)
                    311:     zlog_debug ("isis_dr_commence l%d", level);
                    312: 
                    313:   /* Lets keep a pause in DR election */
                    314:   circuit->u.bc.run_dr_elect[level - 1] = 0;
                    315:   if (level == 1)
                    316:     THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1,
                    317:                     circuit, 2 * circuit->hello_interval[0]);
                    318:   else
                    319:     THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[1], isis_run_dr_l2,
                    320:                     circuit, 2 * circuit->hello_interval[1]);
                    321:   circuit->u.bc.is_dr[level - 1] = 1;
                    322: 
                    323:   if (level == 1)
                    324:     {
                    325:       memcpy (old_dr, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
                    326:       LSP_FRAGMENT (old_dr) = 0;
                    327:       if (LSP_PSEUDO_ID (old_dr))
                    328:        {
                    329:          /* there was a dr elected, purge its LSPs from the db */
                    330:          lsp_purge_dr (old_dr, circuit, level);
                    331:        }
                    332:       memcpy (circuit->u.bc.l1_desig_is, isis->sysid, ISIS_SYS_ID_LEN);
                    333:       *(circuit->u.bc.l1_desig_is + ISIS_SYS_ID_LEN) = circuit->circuit_id;
                    334: 
                    335:       assert (circuit->circuit_id);    /* must be non-zero */
                    336:       /*    if (circuit->t_send_l1_psnp)
                    337:          thread_cancel (circuit->t_send_l1_psnp); */
                    338:       lsp_l1_pseudo_generate (circuit);
                    339: 
                    340:       THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[0]);
                    341:       THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1,
                    342:                       circuit, 2 * circuit->hello_interval[0]);
                    343: 
                    344:       THREAD_TIMER_ON (master, circuit->t_send_csnp[0], send_l1_csnp, circuit,
                    345:                       isis_jitter (circuit->csnp_interval[level - 1],
                    346:                                    CSNP_JITTER));
                    347: 
                    348:     }
                    349:   else
                    350:     {
                    351:       memcpy (old_dr, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
                    352:       LSP_FRAGMENT (old_dr) = 0;
                    353:       if (LSP_PSEUDO_ID (old_dr))
                    354:        {
                    355:          /* there was a dr elected, purge its LSPs from the db */
                    356:          lsp_purge_dr (old_dr, circuit, level);
                    357:        }
                    358:       memcpy (circuit->u.bc.l2_desig_is, isis->sysid, ISIS_SYS_ID_LEN);
                    359:       *(circuit->u.bc.l2_desig_is + ISIS_SYS_ID_LEN) = circuit->circuit_id;
                    360: 
                    361:       assert (circuit->circuit_id);    /* must be non-zero */
                    362:       /*    if (circuit->t_send_l1_psnp)
                    363:          thread_cancel (circuit->t_send_l1_psnp); */
                    364:       lsp_l2_pseudo_generate (circuit);
                    365: 
                    366:       THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[1]);
                    367:       THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[1], isis_run_dr_l2,
                    368:                       circuit, 2 * circuit->hello_interval[1]);
                    369: 
                    370:       THREAD_TIMER_ON (master, circuit->t_send_csnp[1], send_l2_csnp, circuit,
                    371:                       isis_jitter (circuit->csnp_interval[level - 1],
                    372:                                    CSNP_JITTER));
                    373:     }
                    374: 
                    375:   thread_add_event (master, isis_event_dis_status_change, circuit, 0);
                    376: 
                    377:   return ISIS_OK;
                    378: }

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