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