File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / isisd / isis_dr.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Oct 9 09:22:28 2012 UTC (11 years, 9 months ago) by misho
Branches: quagga, MAIN
CVS tags: v1_0_20160315, v0_99_22p0, v0_99_22, v0_99_21, 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: 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: 
  137:   own_prio = circuit->priority[level - 1];
  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);
  144:       return ISIS_WARNING;
  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:       /*
  188:        * Could not find the DR - means we are alone. Resign if we were DR.
  189:        */
  190:       if (circuit->u.bc.is_dr[level - 1])
  191:         retval = isis_dr_resign (circuit, level);
  192:       list_delete (list);
  193:       return retval;
  194:     }
  195: 
  196:   /*
  197:    * Now we have the DR adjacency, compare it to self
  198:    */
  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))
  202:     {
  203:       adj_dr->dis_record[level - 1].dis = ISIS_IS_NOT_DIS;
  204:       adj_dr->dis_record[level - 1].last_dis_change = time (NULL);
  205: 
  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);
  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])
  232:         retval = isis_dr_resign (circuit, level);
  233:     }
  234:   list_delete (list);
  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]);
  249:   circuit->lsp_regenerate_pending[level - 1] = 0;
  250: 
  251:   memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
  252:   LSP_PSEUDO_ID (id) = circuit->circuit_id;
  253:   LSP_FRAGMENT (id) = 0;
  254:   lsp_purge_pseudo (id, circuit, level);
  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 */
  313: 	  lsp_purge_pseudo (old_dr, circuit, level);
  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); */
  321:       lsp_generate_pseudo (circuit, 1);
  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 */
  339: 	  lsp_purge_pseudo (old_dr, circuit, level);
  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); */
  347:       lsp_generate_pseudo (circuit, 2);
  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>