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>