File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / isisd / isis_dr.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:26:11 2012 UTC (12 years, 4 months ago) by misho
Branches: quagga, MAIN
CVS tags: v0_99_20_1, v0_99_20, HEAD
quagga

    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>