]> git.proxmox.com Git - mirror_frr.git/blame - isisd/isis_dr.c
lib: enforce vrf_name_to_id by returning default_vrf when name is null
[mirror_frr.git] / isisd / isis_dr.c
CommitLineData
eb5d44eb 1/*
2 * IS-IS Rout(e)ing protocol - isis_dr.c
d62a17ae 3 * IS-IS designated router related routines
eb5d44eb 4 *
5 * Copyright (C) 2001,2002 Sampo Saaristo
d62a17ae 6 * Tampere University of Technology
eb5d44eb 7 * Institute of Communications Engineering
8 *
d62a17ae 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)
eb5d44eb 12 * any later version.
13 *
d62a17ae 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
eb5d44eb 17 * more details.
896014f4
DL
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; see the file COPYING; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
eb5d44eb 22 */
23
24
25#include <zebra.h>
eb5d44eb 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"
eb5d44eb 45#include "isisd/isis_lsp.h"
46#include "isisd/isis_dr.h"
47#include "isisd/isis_events.h"
48
d62a17ae 49const char *isis_disflag2string(int disflag)
f390d2c7 50{
eb5d44eb 51
d62a17ae 52 switch (disflag) {
53 case ISIS_IS_NOT_DIS:
54 return "is not DIS";
55 case ISIS_IS_DIS:
56 return "is DIS";
57 case ISIS_WAS_DIS:
58 return "was DIS";
59 default:
60 return "unknown DIS state";
61 }
62 return NULL; /* not reached */
eb5d44eb 63}
64
7c4f7aab 65int isis_run_dr(struct thread *thread)
eb5d44eb 66{
7c4f7aab 67 struct isis_circuit_arg *arg = THREAD_ARG(thread);
f390d2c7 68
7c4f7aab 69 assert(arg);
f390d2c7 70
7c4f7aab
CF
71 struct isis_circuit *circuit = arg->circuit;
72 int level = arg->level;
eb5d44eb 73
d62a17ae 74 assert(circuit);
eb5d44eb 75
7c4f7aab
CF
76 if (circuit->circ_type != CIRCUIT_T_BROADCAST) {
77 zlog_warn("%s: scheduled for non broadcast circuit from %s:%d",
78 __func__, thread->schedfrom, thread->schedfrom_line);
79 return ISIS_WARNING;
80 }
f390d2c7 81
7c4f7aab
CF
82 if (circuit->u.bc.run_dr_elect[level - 1])
83 zlog_warn("isis_run_dr(): run_dr_elect already set for l%d", level);
f390d2c7 84
7c4f7aab
CF
85 circuit->u.bc.t_run_dr[level - 1] = NULL;
86 circuit->u.bc.run_dr_elect[level - 1] = 1;
f390d2c7 87
d62a17ae 88 return ISIS_OK;
eb5d44eb 89}
90
d62a17ae 91static int isis_check_dr_change(struct isis_adjacency *adj, int level)
eb5d44eb 92{
d62a17ae 93 int i;
94
95 if (adj->dis_record[level - 1].dis
96 != adj->dis_record[(1 * ISIS_LEVELS) + level - 1].dis)
97 /* was there a DIS state transition ? */
eb5d44eb 98 {
d62a17ae 99 adj->dischanges[level - 1]++;
100 /* ok rotate the history list through */
101 for (i = DIS_RECORDS - 1; i > 0; i--) {
102 adj->dis_record[(i * ISIS_LEVELS) + level - 1].dis =
103 adj->dis_record[((i - 1) * ISIS_LEVELS) + level
104 - 1]
105 .dis;
106 adj->dis_record[(i * ISIS_LEVELS) + level - 1]
107 .last_dis_change =
108 adj->dis_record[((i - 1) * ISIS_LEVELS) + level
109 - 1]
110 .last_dis_change;
111 }
eb5d44eb 112 }
d62a17ae 113 return ISIS_OK;
eb5d44eb 114}
115
d62a17ae 116int isis_dr_elect(struct isis_circuit *circuit, int level)
eb5d44eb 117{
d62a17ae 118 struct list *adjdb;
119 struct listnode *node;
120 struct isis_adjacency *adj, *adj_dr = NULL;
121 struct list *list = list_new();
d7c0a89a 122 uint8_t own_prio;
d62a17ae 123 int biggest_prio = -1;
124 int cmp_res, retval = ISIS_OK;
125
126 own_prio = circuit->priority[level - 1];
127 adjdb = circuit->u.bc.adjdb[level - 1];
128
129 if (!adjdb) {
130 zlog_warn("isis_dr_elect() adjdb == NULL");
6a154c88 131 list_delete(&list);
d62a17ae 132 return ISIS_WARNING;
f390d2c7 133 }
d62a17ae 134 isis_adj_build_up_list(adjdb, list);
135
136 /*
137 * Loop the adjacencies and find the one with the biggest priority
138 */
139 for (ALL_LIST_ELEMENTS_RO(list, node, adj)) {
140 /* clear flag for show output */
141 adj->dis_record[level - 1].dis = ISIS_IS_NOT_DIS;
142 adj->dis_record[level - 1].last_dis_change = time(NULL);
143
144 if (adj->prio[level - 1] > biggest_prio) {
145 biggest_prio = adj->prio[level - 1];
146 adj_dr = adj;
147 } else if (adj->prio[level - 1] == biggest_prio) {
148 /*
149 * Comparison of MACs breaks a tie
150 */
151 if (adj_dr) {
152 cmp_res = memcmp(adj_dr->snpa, adj->snpa,
153 ETH_ALEN);
154 if (cmp_res < 0) {
155 adj_dr = adj;
156 }
157 if (cmp_res == 0)
158 zlog_warn(
159 "isis_dr_elect(): multiple adjacencies with same SNPA");
160 } else {
161 adj_dr = adj;
162 }
f390d2c7 163 }
f390d2c7 164 }
d62a17ae 165
166 if (!adj_dr) {
167 /*
168 * Could not find the DR - means we are alone. Resign if we were
169 * DR.
170 */
171 if (circuit->u.bc.is_dr[level - 1])
172 retval = isis_dr_resign(circuit, level);
6a154c88 173 list_delete(&list);
d62a17ae 174 return retval;
175 }
176
177 /*
178 * Now we have the DR adjacency, compare it to self
179 */
180 if (adj_dr->prio[level - 1] < own_prio
181 || (adj_dr->prio[level - 1] == own_prio
182 && memcmp(adj_dr->snpa, circuit->u.bc.snpa, ETH_ALEN) < 0)) {
183 adj_dr->dis_record[level - 1].dis = ISIS_IS_NOT_DIS;
184 adj_dr->dis_record[level - 1].last_dis_change = time(NULL);
185
186 /* rotate the history log */
187 for (ALL_LIST_ELEMENTS_RO(list, node, adj))
188 isis_check_dr_change(adj, level);
189
190 /* We are the DR, commence DR */
191 if (circuit->u.bc.is_dr[level - 1] == 0 && listcount(list) > 0)
192 retval = isis_dr_commence(circuit, level);
193 } else {
194 /* ok we have found the DIS - lets mark the adjacency */
195 /* set flag for show output */
196 adj_dr->dis_record[level - 1].dis = ISIS_IS_DIS;
197 adj_dr->dis_record[level - 1].last_dis_change = time(NULL);
198
199 /* now loop through a second time to check if there has been a
200 * DIS change
201 * if yes rotate the history log
202 */
203
204 for (ALL_LIST_ELEMENTS_RO(list, node, adj))
205 isis_check_dr_change(adj, level);
206
207 /*
208 * We are not DR - if we were -> resign
209 */
210 if (circuit->u.bc.is_dr[level - 1])
211 retval = isis_dr_resign(circuit, level);
212 }
6a154c88 213 list_delete(&list);
d62a17ae 214 return retval;
eb5d44eb 215}
216
d62a17ae 217int isis_dr_resign(struct isis_circuit *circuit, int level)
eb5d44eb 218{
d7c0a89a 219 uint8_t id[ISIS_SYS_ID_LEN + 2];
f390d2c7 220
d62a17ae 221 zlog_debug("isis_dr_resign l%d", level);
eb5d44eb 222
d62a17ae 223 circuit->u.bc.is_dr[level - 1] = 0;
224 circuit->u.bc.run_dr_elect[level - 1] = 0;
225 THREAD_TIMER_OFF(circuit->u.bc.t_run_dr[level - 1]);
226 THREAD_TIMER_OFF(circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
227 circuit->lsp_regenerate_pending[level - 1] = 0;
f390d2c7 228
d62a17ae 229 memcpy(id, isis->sysid, ISIS_SYS_ID_LEN);
230 LSP_PSEUDO_ID(id) = circuit->circuit_id;
231 LSP_FRAGMENT(id) = 0;
232 lsp_purge_pseudo(id, circuit, level);
eb5d44eb 233
d62a17ae 234 if (level == 1) {
235 memset(circuit->u.bc.l1_desig_is, 0, ISIS_SYS_ID_LEN + 1);
f390d2c7 236
d62a17ae 237 thread_add_timer(master, send_l1_psnp, circuit,
238 isis_jitter(circuit->psnp_interval[level - 1],
239 PSNP_JITTER),
240 &circuit->t_send_psnp[0]);
241 } else {
242 memset(circuit->u.bc.l2_desig_is, 0, ISIS_SYS_ID_LEN + 1);
f390d2c7 243
d62a17ae 244 thread_add_timer(master, send_l2_psnp, circuit,
245 isis_jitter(circuit->psnp_interval[level - 1],
246 PSNP_JITTER),
247 &circuit->t_send_psnp[1]);
248 }
f390d2c7 249
7c4f7aab
CF
250 THREAD_TIMER_OFF(circuit->t_send_csnp[level - 1]);
251
252 thread_add_timer(master, isis_run_dr,
253 &circuit->level_arg[level - 1],
254 2 * circuit->hello_interval[level - 1],
255 &circuit->u.bc.t_run_dr[level - 1]);
256
257
d62a17ae 258 thread_add_event(master, isis_event_dis_status_change, circuit, 0,
259 NULL);
eb5d44eb 260
d62a17ae 261 return ISIS_OK;
eb5d44eb 262}
263
d62a17ae 264int isis_dr_commence(struct isis_circuit *circuit, int level)
eb5d44eb 265{
d7c0a89a 266 uint8_t old_dr[ISIS_SYS_ID_LEN + 2];
d62a17ae 267
268 if (isis->debugs & DEBUG_EVENTS)
269 zlog_debug("isis_dr_commence l%d", level);
270
271 /* Lets keep a pause in DR election */
272 circuit->u.bc.run_dr_elect[level - 1] = 0;
d62a17ae 273 circuit->u.bc.is_dr[level - 1] = 1;
274
275 if (level == 1) {
276 memcpy(old_dr, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
277 LSP_FRAGMENT(old_dr) = 0;
278 if (LSP_PSEUDO_ID(old_dr)) {
279 /* there was a dr elected, purge its LSPs from the db */
280 lsp_purge_pseudo(old_dr, circuit, level);
281 }
282 memcpy(circuit->u.bc.l1_desig_is, isis->sysid, ISIS_SYS_ID_LEN);
283 *(circuit->u.bc.l1_desig_is + ISIS_SYS_ID_LEN) =
284 circuit->circuit_id;
285
286 assert(circuit->circuit_id); /* must be non-zero */
287 /* if (circuit->t_send_l1_psnp)
288 thread_cancel (circuit->t_send_l1_psnp); */
289 lsp_generate_pseudo(circuit, 1);
290
d62a17ae 291 thread_add_timer(master, send_l1_csnp, circuit,
292 isis_jitter(circuit->csnp_interval[level - 1],
293 CSNP_JITTER),
294 &circuit->t_send_csnp[0]);
295
296 } else {
297 memcpy(old_dr, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
298 LSP_FRAGMENT(old_dr) = 0;
299 if (LSP_PSEUDO_ID(old_dr)) {
300 /* there was a dr elected, purge its LSPs from the db */
301 lsp_purge_pseudo(old_dr, circuit, level);
302 }
303 memcpy(circuit->u.bc.l2_desig_is, isis->sysid, ISIS_SYS_ID_LEN);
304 *(circuit->u.bc.l2_desig_is + ISIS_SYS_ID_LEN) =
305 circuit->circuit_id;
306
307 assert(circuit->circuit_id); /* must be non-zero */
308 /* if (circuit->t_send_l1_psnp)
309 thread_cancel (circuit->t_send_l1_psnp); */
310 lsp_generate_pseudo(circuit, 2);
311
d62a17ae 312 thread_add_timer(master, send_l2_csnp, circuit,
313 isis_jitter(circuit->csnp_interval[level - 1],
314 CSNP_JITTER),
315 &circuit->t_send_csnp[1]);
f390d2c7 316 }
eb5d44eb 317
0a5e562a
CF
318 thread_add_timer(master, isis_run_dr,
319 &circuit->level_arg[level - 1],
320 2 * circuit->hello_interval[level - 1],
321 &circuit->u.bc.t_run_dr[level - 1]);
d62a17ae 322 thread_add_event(master, isis_event_dis_status_change, circuit, 0,
323 NULL);
f390d2c7 324
d62a17ae 325 return ISIS_OK;
eb5d44eb 326}