Annotation of embedaddon/quagga/isisd/isis_dr.c, revision 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>