isis_dr.c 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  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. * You should have received a copy of the GNU General Public License along
  19. * with this program; if not, write to the Free Software Foundation, Inc.,
  20. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21. */
  22. #include <zebra.h>
  23. #include "log.h"
  24. #include "hash.h"
  25. #include "thread.h"
  26. #include "linklist.h"
  27. #include "vty.h"
  28. #include "stream.h"
  29. #include "if.h"
  30. #include "isisd/dict.h"
  31. #include "isisd/isis_constants.h"
  32. #include "isisd/isis_common.h"
  33. #include "isisd/isis_misc.h"
  34. #include "isisd/isis_flags.h"
  35. #include "isisd/isis_circuit.h"
  36. #include "isisd/isisd.h"
  37. #include "isisd/isis_adjacency.h"
  38. #include "isisd/isis_constants.h"
  39. #include "isisd/isis_pdu.h"
  40. #include "isisd/isis_tlv.h"
  41. #include "isisd/isis_lsp.h"
  42. #include "isisd/isis_dr.h"
  43. #include "isisd/isis_events.h"
  44. const char *
  45. isis_disflag2string (int disflag)
  46. {
  47. switch (disflag)
  48. {
  49. case ISIS_IS_NOT_DIS:
  50. return "is not DIS";
  51. case ISIS_IS_DIS:
  52. return "is DIS";
  53. case ISIS_WAS_DIS:
  54. return "was DIS";
  55. default:
  56. return "unknown DIS state";
  57. }
  58. return NULL; /* not reached */
  59. }
  60. int
  61. isis_run_dr_l1 (struct thread *thread)
  62. {
  63. struct isis_circuit *circuit;
  64. circuit = THREAD_ARG (thread);
  65. assert (circuit);
  66. if (circuit->u.bc.run_dr_elect[0])
  67. zlog_warn ("isis_run_dr(): run_dr_elect already set for l1");
  68. circuit->u.bc.t_run_dr[0] = NULL;
  69. circuit->u.bc.run_dr_elect[0] = 1;
  70. return ISIS_OK;
  71. }
  72. int
  73. isis_run_dr_l2 (struct thread *thread)
  74. {
  75. struct isis_circuit *circuit;
  76. circuit = THREAD_ARG (thread);
  77. assert (circuit);
  78. if (circuit->u.bc.run_dr_elect[1])
  79. zlog_warn ("isis_run_dr(): run_dr_elect already set for l2");
  80. circuit->u.bc.t_run_dr[1] = NULL;
  81. circuit->u.bc.run_dr_elect[1] = 1;
  82. return ISIS_OK;
  83. }
  84. static int
  85. isis_check_dr_change (struct isis_adjacency *adj, int level)
  86. {
  87. int i;
  88. if (adj->dis_record[level - 1].dis !=
  89. adj->dis_record[(1 * ISIS_LEVELS) + level - 1].dis)
  90. /* was there a DIS state transition ? */
  91. {
  92. adj->dischanges[level - 1]++;
  93. /* ok rotate the history list through */
  94. for (i = DIS_RECORDS - 1; i > 0; i--)
  95. {
  96. adj->dis_record[(i * ISIS_LEVELS) + level - 1].dis =
  97. adj->dis_record[((i - 1) * ISIS_LEVELS) + level - 1].dis;
  98. adj->dis_record[(i * ISIS_LEVELS) + level - 1].last_dis_change =
  99. adj->dis_record[((i - 1) * ISIS_LEVELS) + level -
  100. 1].last_dis_change;
  101. }
  102. }
  103. return ISIS_OK;
  104. }
  105. int
  106. isis_dr_elect (struct isis_circuit *circuit, int level)
  107. {
  108. struct list *adjdb;
  109. struct listnode *node;
  110. struct isis_adjacency *adj, *adj_dr = NULL;
  111. struct list *list = list_new ();
  112. u_char own_prio;
  113. int biggest_prio = -1;
  114. int cmp_res, retval = ISIS_OK;
  115. own_prio = circuit->priority[level - 1];
  116. adjdb = circuit->u.bc.adjdb[level - 1];
  117. if (!adjdb)
  118. {
  119. zlog_warn ("isis_dr_elect() adjdb == NULL");
  120. list_delete (list);
  121. return ISIS_WARNING;
  122. }
  123. isis_adj_build_up_list (adjdb, list);
  124. /*
  125. * Loop the adjacencies and find the one with the biggest priority
  126. */
  127. for (ALL_LIST_ELEMENTS_RO (list, node, adj))
  128. {
  129. /* clear flag for show output */
  130. adj->dis_record[level - 1].dis = ISIS_IS_NOT_DIS;
  131. adj->dis_record[level - 1].last_dis_change = time (NULL);
  132. if (adj->prio[level - 1] > biggest_prio)
  133. {
  134. biggest_prio = adj->prio[level - 1];
  135. adj_dr = adj;
  136. }
  137. else if (adj->prio[level - 1] == biggest_prio)
  138. {
  139. /*
  140. * Comparison of MACs breaks a tie
  141. */
  142. if (adj_dr)
  143. {
  144. cmp_res = memcmp (adj_dr->snpa, adj->snpa, ETH_ALEN);
  145. if (cmp_res < 0)
  146. {
  147. adj_dr = adj;
  148. }
  149. if (cmp_res == 0)
  150. zlog_warn
  151. ("isis_dr_elect(): multiple adjacencies with same SNPA");
  152. }
  153. else
  154. {
  155. adj_dr = adj;
  156. }
  157. }
  158. }
  159. if (!adj_dr)
  160. {
  161. /*
  162. * Could not find the DR - means we are alone. Resign if we were DR.
  163. */
  164. if (circuit->u.bc.is_dr[level - 1])
  165. retval = isis_dr_resign (circuit, level);
  166. list_delete (list);
  167. return retval;
  168. }
  169. /*
  170. * Now we have the DR adjacency, compare it to self
  171. */
  172. if (adj_dr->prio[level - 1] < own_prio ||
  173. (adj_dr->prio[level - 1] == own_prio &&
  174. memcmp (adj_dr->snpa, circuit->u.bc.snpa, ETH_ALEN) < 0))
  175. {
  176. adj_dr->dis_record[level - 1].dis = ISIS_IS_NOT_DIS;
  177. adj_dr->dis_record[level - 1].last_dis_change = time (NULL);
  178. /* rotate the history log */
  179. for (ALL_LIST_ELEMENTS_RO (list, node, adj))
  180. isis_check_dr_change (adj, level);
  181. /* We are the DR, commence DR */
  182. if (circuit->u.bc.is_dr[level - 1] == 0 && listcount (list) > 0)
  183. retval = isis_dr_commence (circuit, level);
  184. }
  185. else
  186. {
  187. /* ok we have found the DIS - lets mark the adjacency */
  188. /* set flag for show output */
  189. adj_dr->dis_record[level - 1].dis = ISIS_IS_DIS;
  190. adj_dr->dis_record[level - 1].last_dis_change = time (NULL);
  191. /* now loop through a second time to check if there has been a DIS change
  192. * if yes rotate the history log
  193. */
  194. for (ALL_LIST_ELEMENTS_RO (list, node, adj))
  195. isis_check_dr_change (adj, level);
  196. /*
  197. * We are not DR - if we were -> resign
  198. */
  199. if (circuit->u.bc.is_dr[level - 1])
  200. retval = isis_dr_resign (circuit, level);
  201. }
  202. list_delete (list);
  203. return retval;
  204. }
  205. int
  206. isis_dr_resign (struct isis_circuit *circuit, int level)
  207. {
  208. u_char id[ISIS_SYS_ID_LEN + 2];
  209. zlog_debug ("isis_dr_resign l%d", level);
  210. circuit->u.bc.is_dr[level - 1] = 0;
  211. circuit->u.bc.run_dr_elect[level - 1] = 0;
  212. THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[level - 1]);
  213. THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
  214. circuit->lsp_regenerate_pending[level - 1] = 0;
  215. memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
  216. LSP_PSEUDO_ID (id) = circuit->circuit_id;
  217. LSP_FRAGMENT (id) = 0;
  218. lsp_purge_pseudo (id, circuit, level);
  219. if (level == 1)
  220. {
  221. memset (circuit->u.bc.l1_desig_is, 0, ISIS_SYS_ID_LEN + 1);
  222. THREAD_TIMER_OFF (circuit->t_send_csnp[0]);
  223. THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1,
  224. circuit, 2 * circuit->hello_interval[0]);
  225. THREAD_TIMER_ON (master, circuit->t_send_psnp[0], send_l1_psnp, circuit,
  226. isis_jitter (circuit->psnp_interval[level - 1],
  227. PSNP_JITTER));
  228. }
  229. else
  230. {
  231. memset (circuit->u.bc.l2_desig_is, 0, ISIS_SYS_ID_LEN + 1);
  232. THREAD_TIMER_OFF (circuit->t_send_csnp[1]);
  233. THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[1], isis_run_dr_l2,
  234. circuit, 2 * circuit->hello_interval[1]);
  235. THREAD_TIMER_ON (master, circuit->t_send_psnp[1], send_l2_psnp, circuit,
  236. isis_jitter (circuit->psnp_interval[level - 1],
  237. PSNP_JITTER));
  238. }
  239. thread_add_event (master, isis_event_dis_status_change, circuit, 0);
  240. return ISIS_OK;
  241. }
  242. int
  243. isis_dr_commence (struct isis_circuit *circuit, int level)
  244. {
  245. u_char old_dr[ISIS_SYS_ID_LEN + 2];
  246. if (isis->debugs & DEBUG_EVENTS)
  247. zlog_debug ("isis_dr_commence l%d", level);
  248. /* Lets keep a pause in DR election */
  249. circuit->u.bc.run_dr_elect[level - 1] = 0;
  250. if (level == 1)
  251. THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1,
  252. circuit, 2 * circuit->hello_interval[0]);
  253. else
  254. THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[1], isis_run_dr_l2,
  255. circuit, 2 * circuit->hello_interval[1]);
  256. circuit->u.bc.is_dr[level - 1] = 1;
  257. if (level == 1)
  258. {
  259. memcpy (old_dr, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
  260. LSP_FRAGMENT (old_dr) = 0;
  261. if (LSP_PSEUDO_ID (old_dr))
  262. {
  263. /* there was a dr elected, purge its LSPs from the db */
  264. lsp_purge_pseudo (old_dr, circuit, level);
  265. }
  266. memcpy (circuit->u.bc.l1_desig_is, isis->sysid, ISIS_SYS_ID_LEN);
  267. *(circuit->u.bc.l1_desig_is + ISIS_SYS_ID_LEN) = circuit->circuit_id;
  268. assert (circuit->circuit_id); /* must be non-zero */
  269. /* if (circuit->t_send_l1_psnp)
  270. thread_cancel (circuit->t_send_l1_psnp); */
  271. lsp_generate_pseudo (circuit, 1);
  272. THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[0]);
  273. THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1,
  274. circuit, 2 * circuit->hello_interval[0]);
  275. THREAD_TIMER_ON (master, circuit->t_send_csnp[0], send_l1_csnp, circuit,
  276. isis_jitter (circuit->csnp_interval[level - 1],
  277. CSNP_JITTER));
  278. }
  279. else
  280. {
  281. memcpy (old_dr, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
  282. LSP_FRAGMENT (old_dr) = 0;
  283. if (LSP_PSEUDO_ID (old_dr))
  284. {
  285. /* there was a dr elected, purge its LSPs from the db */
  286. lsp_purge_pseudo (old_dr, circuit, level);
  287. }
  288. memcpy (circuit->u.bc.l2_desig_is, isis->sysid, ISIS_SYS_ID_LEN);
  289. *(circuit->u.bc.l2_desig_is + ISIS_SYS_ID_LEN) = circuit->circuit_id;
  290. assert (circuit->circuit_id); /* must be non-zero */
  291. /* if (circuit->t_send_l1_psnp)
  292. thread_cancel (circuit->t_send_l1_psnp); */
  293. lsp_generate_pseudo (circuit, 2);
  294. THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[1]);
  295. THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[1], isis_run_dr_l2,
  296. circuit, 2 * circuit->hello_interval[1]);
  297. THREAD_TIMER_ON (master, circuit->t_send_csnp[1], send_l2_csnp, circuit,
  298. isis_jitter (circuit->csnp_interval[level - 1],
  299. CSNP_JITTER));
  300. }
  301. thread_add_event (master, isis_event_dis_status_change, circuit, 0);
  302. return ISIS_OK;
  303. }