]>
Commit | Line | Data |
---|---|---|
1cbf96a8 | 1 | /** |
2 | * isis_ldp_sync.c: ISIS LDP-IGP Sync handling routines | |
3 | * Copyright (C) 2020 Volta Networks, Inc. | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify it | |
6 | * under the terms of the GNU General Public License as published by the Free | |
7 | * Software Foundation; either version 2 of the License, or (at your option) | |
8 | * any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
13 | * more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License along | |
16 | * with this program; see the file COPYING; if not, write to the Free Software | |
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
18 | */ | |
19 | ||
20 | #include <zebra.h> | |
21 | #include <string.h> | |
22 | ||
23 | #include "monotime.h" | |
24 | #include "memory.h" | |
25 | #include "thread.h" | |
26 | #include "prefix.h" | |
27 | #include "table.h" | |
28 | #include "vty.h" | |
29 | #include "command.h" | |
30 | #include "plist.h" | |
31 | #include "log.h" | |
32 | #include "zclient.h" | |
33 | #include <lib/json.h> | |
34 | #include "defaults.h" | |
35 | #include "ldp_sync.h" | |
36 | ||
37 | #include "isisd/isis_constants.h" | |
38 | #include "isisd/isis_common.h" | |
39 | #include "isisd/isis_flags.h" | |
40 | #include "isisd/isis_circuit.h" | |
41 | #include "isisd/isis_lsp.h" | |
42 | #include "isisd/isis_pdu.h" | |
43 | #include "isisd/isis_network.h" | |
44 | #include "isisd/isis_misc.h" | |
45 | #include "isisd/isis_constants.h" | |
46 | #include "isisd/isis_adjacency.h" | |
47 | #include "isisd/isis_dr.h" | |
48 | #include "isisd/isisd.h" | |
49 | #include "isisd/isis_csm.h" | |
50 | #include "isisd/isis_events.h" | |
51 | #include "isisd/isis_te.h" | |
52 | #include "isisd/isis_mt.h" | |
53 | #include "isisd/isis_errors.h" | |
54 | #include "isisd/isis_tx_queue.h" | |
55 | #include "isisd/isis_nb.h" | |
56 | #include "isisd/isis_ldp_sync.h" | |
57 | ||
58 | extern struct zclient *zclient; | |
59 | ||
60 | /* | |
61 | * LDP-SYNC msg between IGP and LDP | |
62 | */ | |
63 | int isis_ldp_sync_state_update(struct ldp_igp_sync_if_state state) | |
64 | { | |
65 | struct interface *ifp; | |
66 | struct isis_circuit *circuit = NULL; | |
67 | struct isis_area *area; | |
1cbf96a8 | 68 | |
69 | /* lookup circuit */ | |
70 | ifp = if_lookup_by_index(state.ifindex, VRF_DEFAULT); | |
71 | if (ifp == NULL) | |
72 | return 0; | |
73 | ||
ec62fbaa IR |
74 | circuit = ifp->info; |
75 | if (circuit == NULL) | |
76 | return 0; | |
1cbf96a8 | 77 | |
78 | /* if isis is not enabled or LDP-SYNC is not configured ignore */ | |
ec62fbaa IR |
79 | area = circuit->area; |
80 | if (area == NULL | |
81 | || !CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) | |
1cbf96a8 | 82 | return 0; |
83 | ||
84 | /* received ldp-sync interface state from LDP */ | |
11106e28 | 85 | ils_debug("%s: rcvd %s from LDP if %s", __func__, |
1cbf96a8 | 86 | state.sync_start ? "sync-start" : "sync-complete", ifp->name); |
87 | if (state.sync_start) | |
88 | isis_ldp_sync_if_start(circuit, false); | |
89 | else | |
90 | isis_ldp_sync_if_complete(circuit); | |
91 | ||
92 | return 0; | |
93 | } | |
94 | ||
95 | int isis_ldp_sync_announce_update(struct ldp_igp_sync_announce announce) | |
96 | { | |
97 | struct isis_area *area; | |
ec62fbaa | 98 | struct listnode *anode, *cnode; |
1cbf96a8 | 99 | struct isis_circuit *circuit; |
100 | struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); | |
101 | ||
ec62fbaa IR |
102 | /* if isis is not enabled ignore */ |
103 | if (!isis) | |
1cbf96a8 | 104 | return 0; |
105 | ||
106 | if (announce.proto != ZEBRA_ROUTE_LDP) | |
107 | return 0; | |
108 | ||
11106e28 | 109 | ils_debug("%s: rcvd announce from LDP", __func__); |
1cbf96a8 | 110 | |
111 | /* LDP just started up: | |
112 | * set cost to LSInfinity | |
113 | * send request to LDP for LDP-SYNC state for each interface | |
1cbf96a8 | 114 | */ |
ec62fbaa IR |
115 | for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) { |
116 | if (!CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) | |
117 | continue; | |
118 | ||
119 | for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit)) | |
1cbf96a8 | 120 | isis_ldp_sync_if_start(circuit, true); |
1cbf96a8 | 121 | } |
122 | ||
1cbf96a8 | 123 | return 0; |
124 | } | |
125 | ||
126 | void isis_ldp_sync_state_req_msg(struct isis_circuit *circuit) | |
127 | { | |
128 | struct ldp_igp_sync_if_state_req request; | |
129 | struct interface *ifp = circuit->interface; | |
130 | ||
11106e28 | 131 | ils_debug("%s: send state request to LDP for %s", __func__, ifp->name); |
1cbf96a8 | 132 | |
f735c2e8 | 133 | memset(&request, 0, sizeof(request)); |
1cbf96a8 | 134 | strlcpy(request.name, ifp->name, sizeof(ifp->name)); |
135 | request.proto = LDP_IGP_SYNC_IF_STATE_REQUEST; | |
136 | request.ifindex = ifp->ifindex; | |
137 | ||
138 | zclient_send_opaque(zclient, LDP_IGP_SYNC_IF_STATE_REQUEST, | |
139 | (uint8_t *)&request, sizeof(request)); | |
140 | } | |
141 | ||
142 | /* | |
143 | * LDP-SYNC general interface routines | |
144 | */ | |
1cbf96a8 | 145 | void isis_ldp_sync_if_start(struct isis_circuit *circuit, |
146 | bool send_state_req) | |
147 | { | |
148 | struct ldp_sync_info *ldp_sync_info; | |
149 | ||
150 | ldp_sync_info = circuit->ldp_sync_info; | |
151 | ||
152 | /* Start LDP-SYNC on this interface: | |
153 | * set cost of interface to LSInfinity so traffic will use different | |
154 | * interface until LDP has learned all labels from peer | |
155 | * start holddown timer if configured | |
156 | * send msg to LDP to get LDP-SYNC state | |
157 | */ | |
158 | if (ldp_sync_info && | |
159 | ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED && | |
160 | ldp_sync_info->state != LDP_IGP_SYNC_STATE_NOT_REQUIRED) { | |
11106e28 | 161 | ils_debug("%s: start on if %s state: %s", __func__, |
1cbf96a8 | 162 | circuit->interface->name, "Holding down until Sync"); |
163 | ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP; | |
164 | isis_ldp_sync_set_if_metric(circuit, true); | |
165 | isis_ldp_sync_holddown_timer_add(circuit); | |
166 | ||
167 | if (send_state_req) | |
168 | isis_ldp_sync_state_req_msg(circuit); | |
169 | } | |
170 | } | |
171 | ||
172 | void isis_ldp_sync_if_complete(struct isis_circuit *circuit) | |
173 | { | |
174 | struct ldp_sync_info *ldp_sync_info; | |
175 | ||
176 | ldp_sync_info = circuit->ldp_sync_info; | |
177 | ||
178 | /* received sync-complete from LDP: | |
179 | * set state to up | |
180 | * stop timer | |
181 | * restore interface cost to original value | |
182 | */ | |
183 | if (ldp_sync_info && ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED) { | |
184 | if (ldp_sync_info->state == LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP) | |
185 | ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_UP; | |
50478845 MS |
186 | |
187 | THREAD_OFF(ldp_sync_info->t_holddown); | |
188 | ||
1cbf96a8 | 189 | isis_ldp_sync_set_if_metric(circuit, true); |
190 | } | |
191 | } | |
192 | ||
193 | void isis_ldp_sync_ldp_fail(struct isis_circuit *circuit) | |
194 | { | |
195 | struct ldp_sync_info *ldp_sync_info; | |
196 | ||
197 | ldp_sync_info = circuit->ldp_sync_info; | |
198 | ||
cb135cc9 | 199 | /* LDP client close detected: |
1cbf96a8 | 200 | * stop holddown timer |
201 | * set cost of interface to LSInfinity so traffic will use different | |
202 | * interface until LDP restarts and has learned all labels from peer | |
203 | */ | |
204 | if (ldp_sync_info && | |
205 | ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED && | |
206 | ldp_sync_info->state != LDP_IGP_SYNC_STATE_NOT_REQUIRED) { | |
50478845 | 207 | THREAD_OFF(ldp_sync_info->t_holddown); |
1cbf96a8 | 208 | ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP; |
209 | isis_ldp_sync_set_if_metric(circuit, true); | |
210 | } | |
211 | } | |
212 | ||
1cbf96a8 | 213 | static int isis_ldp_sync_adj_state_change(struct isis_adjacency *adj) |
214 | { | |
215 | struct isis_circuit *circuit = adj->circuit; | |
ec62fbaa IR |
216 | struct ldp_sync_info *ldp_sync_info = circuit->ldp_sync_info; |
217 | struct isis_area *area = circuit->area; | |
1cbf96a8 | 218 | |
ec62fbaa | 219 | if (!CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE) |
096f7609 | 220 | || circuit->interface->vrf->vrf_id != VRF_DEFAULT |
ec62fbaa | 221 | || if_is_loopback(circuit->interface)) |
1cbf96a8 | 222 | return 0; |
223 | ||
1cbf96a8 | 224 | if (ldp_sync_info->enabled != LDP_IGP_SYNC_ENABLED) |
225 | return 0; | |
226 | ||
227 | if (adj->adj_state == ISIS_ADJ_UP) { | |
228 | if (circuit->circ_type == CIRCUIT_T_P2P || | |
229 | if_is_pointopoint(circuit->interface)) { | |
230 | /* If LDP-SYNC is configure on interface then start */ | |
231 | ldp_sync_info->state = | |
232 | LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP; | |
233 | isis_ldp_sync_if_start(circuit, true); | |
234 | } else { | |
235 | /* non ptop link so don't run ldp-sync */ | |
236 | ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED; | |
237 | isis_ldp_sync_set_if_metric(circuit, true); | |
238 | } | |
239 | } else { | |
240 | /* If LDP-SYNC is configure on this interface then stop it */ | |
241 | if (circuit->circ_type == CIRCUIT_T_P2P || | |
242 | if_is_pointopoint(circuit->interface)) | |
243 | ldp_sync_info->state = | |
244 | LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP; | |
245 | else | |
246 | ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED; | |
247 | ||
11106e28 | 248 | ils_debug("%s: down on if %s", __func__, |
249 | circuit->interface->name); | |
1cbf96a8 | 250 | ldp_sync_if_down(circuit->ldp_sync_info); |
251 | } | |
252 | ||
253 | return 0; | |
254 | } | |
255 | ||
256 | bool isis_ldp_sync_if_metric_config(struct isis_circuit *circuit, int level, | |
257 | int metric) | |
258 | { | |
259 | struct ldp_sync_info *ldp_sync_info = circuit->ldp_sync_info; | |
ec62fbaa | 260 | struct isis_area *area = circuit->area; |
1cbf96a8 | 261 | |
262 | /* configured interface metric has been changed: | |
263 | * if LDP-IGP Sync is running and metric has been set to LSInfinity | |
264 | * change saved value so when ldp-sync completes proper metric is | |
265 | * restored | |
266 | */ | |
ec62fbaa IR |
267 | if (area && CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE) |
268 | && ldp_sync_info != NULL) { | |
1cbf96a8 | 269 | |
270 | if (CHECK_FLAG(ldp_sync_info->flags, | |
271 | LDP_SYNC_FLAG_SET_METRIC)) { | |
272 | ldp_sync_info->metric[level-1] = metric; | |
273 | ldp_sync_info->metric[level-1] = metric; | |
274 | return false; | |
275 | } | |
276 | } | |
277 | return true; | |
278 | } | |
279 | ||
280 | void isis_ldp_sync_set_if_metric(struct isis_circuit *circuit, bool run_regen) | |
281 | { | |
282 | struct ldp_sync_info *ldp_sync_info; | |
283 | ||
284 | /* set interface metric: | |
285 | * if LDP-IGP Sync is starting set metric so interface | |
286 | * is used only as last resort | |
287 | * else restore metric to original value | |
288 | */ | |
289 | if (circuit->ldp_sync_info == NULL || circuit->area == NULL) | |
290 | return; | |
291 | ||
292 | ldp_sync_info = circuit->ldp_sync_info; | |
293 | if (ldp_sync_if_is_enabled(ldp_sync_info)) { | |
294 | /* if metric already set to LSInfinity just return */ | |
295 | if (CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_SET_METRIC)) | |
296 | return; | |
297 | ||
298 | SET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_SET_METRIC); | |
299 | if (circuit->is_type & IS_LEVEL_1) { | |
300 | if (circuit->area->newmetric) { | |
301 | ldp_sync_info->metric[0] = | |
302 | circuit->te_metric[0]; | |
35f70ed3 RW |
303 | circuit->te_metric[0] = |
304 | ISIS_WIDE_METRIC_INFINITY; | |
1cbf96a8 | 305 | } else { |
306 | ldp_sync_info->metric[0] = circuit->metric[0]; | |
35f70ed3 RW |
307 | circuit->metric[0] = |
308 | ISIS_NARROW_METRIC_INFINITY; | |
1cbf96a8 | 309 | } |
310 | } | |
311 | if (circuit->is_type & IS_LEVEL_2) { | |
312 | if (circuit->area->newmetric) { | |
313 | ldp_sync_info->metric[1] = | |
314 | circuit->te_metric[1]; | |
35f70ed3 RW |
315 | circuit->te_metric[1] = |
316 | ISIS_WIDE_METRIC_INFINITY; | |
1cbf96a8 | 317 | } else { |
318 | ldp_sync_info->metric[1] = circuit->metric[1]; | |
35f70ed3 RW |
319 | circuit->metric[1] = |
320 | ISIS_NARROW_METRIC_INFINITY; | |
1cbf96a8 | 321 | } |
322 | } | |
323 | } else { | |
324 | /* if metric already restored just return */ | |
325 | if (!CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_SET_METRIC)) | |
326 | return; | |
327 | ||
328 | UNSET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_SET_METRIC); | |
329 | if (circuit->is_type & IS_LEVEL_1) { | |
330 | circuit->te_metric[0] = ldp_sync_info->metric[0]; | |
331 | circuit->metric[0] = ldp_sync_info->metric[0]; | |
332 | } | |
333 | if (circuit->is_type & IS_LEVEL_2) { | |
334 | circuit->te_metric[1] = ldp_sync_info->metric[1]; | |
335 | circuit->metric[1] = ldp_sync_info->metric[1]; | |
336 | } | |
337 | } | |
338 | ||
339 | if (run_regen) | |
340 | lsp_regenerate_schedule(circuit->area, circuit->is_type, 0); | |
341 | } | |
342 | ||
343 | ||
344 | /* | |
345 | * LDP-SYNC holddown timer routines | |
346 | */ | |
cc9f21da | 347 | static void isis_ldp_sync_holddown_timer(struct thread *thread) |
1cbf96a8 | 348 | { |
349 | struct isis_circuit *circuit; | |
350 | struct ldp_sync_info *ldp_sync_info; | |
351 | ||
352 | /* holddown timer expired: | |
353 | * didn't receive msg from LDP indicating sync-complete | |
354 | * restore interface cost to original value | |
355 | */ | |
356 | circuit = THREAD_ARG(thread); | |
357 | if (circuit->ldp_sync_info == NULL) | |
cc9f21da | 358 | return; |
1cbf96a8 | 359 | |
360 | ldp_sync_info = circuit->ldp_sync_info; | |
361 | ||
362 | ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_UP; | |
363 | ldp_sync_info->t_holddown = NULL; | |
364 | ||
11106e28 | 365 | ils_debug("%s: holddown timer expired for %s state:sync achieved", |
366 | __func__, circuit->interface->name); | |
1cbf96a8 | 367 | |
368 | isis_ldp_sync_set_if_metric(circuit, true); | |
1cbf96a8 | 369 | } |
370 | ||
371 | void isis_ldp_sync_holddown_timer_add(struct isis_circuit *circuit) | |
372 | { | |
373 | struct ldp_sync_info *ldp_sync_info; | |
374 | ||
375 | ldp_sync_info = circuit->ldp_sync_info; | |
376 | ||
377 | /* Start holddown timer: | |
378 | * this timer is used to keep interface cost at LSInfinity | |
379 | * once expires returns cost to original value | |
380 | * if timer is already running or holddown time is off just return | |
381 | */ | |
382 | if (ldp_sync_info->t_holddown || | |
383 | ldp_sync_info->holddown == LDP_IGP_SYNC_HOLDDOWN_DEFAULT) | |
384 | return; | |
385 | ||
11106e28 | 386 | ils_debug("%s: start holddown timer for %s time %d", __func__, |
1cbf96a8 | 387 | circuit->interface->name, ldp_sync_info->holddown); |
388 | ||
389 | thread_add_timer(master, isis_ldp_sync_holddown_timer, | |
390 | circuit, ldp_sync_info->holddown, | |
391 | &ldp_sync_info->t_holddown); | |
392 | } | |
393 | ||
cb135cc9 KS |
394 | /* |
395 | * LDP-SYNC handle client close routine | |
396 | */ | |
397 | void isis_ldp_sync_handle_client_close(struct zapi_client_close_info *info) | |
398 | { | |
399 | struct isis_area *area; | |
ec62fbaa | 400 | struct listnode *anode, *cnode; |
cb135cc9 | 401 | struct isis_circuit *circuit; |
cb135cc9 KS |
402 | struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); |
403 | ||
ec62fbaa IR |
404 | /* if isis is not enabled ignore */ |
405 | if (!isis) | |
cb135cc9 KS |
406 | return; |
407 | ||
408 | /* Check if the LDP main client session closed */ | |
409 | if (info->proto != ZEBRA_ROUTE_LDP || info->session_id == 0) | |
410 | return; | |
411 | ||
412 | /* Handle the zebra notification that the LDP client session closed. | |
413 | * set cost to LSInfinity | |
414 | * send request to LDP for LDP-SYNC state for each interface | |
415 | */ | |
11106e28 | 416 | zlog_err("%s: LDP down", __func__); |
cb135cc9 | 417 | |
ec62fbaa IR |
418 | for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) { |
419 | if (!CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) | |
420 | continue; | |
421 | ||
422 | for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit)) | |
c3783ac0 | 423 | isis_ldp_sync_ldp_fail(circuit); |
cb135cc9 KS |
424 | } |
425 | } | |
426 | ||
1cbf96a8 | 427 | /* |
428 | * LDP-SYNC routes used by set commands. | |
429 | */ | |
430 | ||
ec62fbaa | 431 | void isis_area_ldp_sync_enable(struct isis_area *area) |
1cbf96a8 | 432 | { |
ec62fbaa IR |
433 | struct isis_circuit *circuit; |
434 | struct listnode *node; | |
435 | ||
436 | if (!CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) { | |
437 | SET_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE); | |
438 | ||
439 | for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) | |
440 | isis_if_ldp_sync_enable(circuit); | |
441 | } | |
442 | } | |
443 | ||
444 | void isis_area_ldp_sync_disable(struct isis_area *area) | |
445 | { | |
446 | struct isis_circuit *circuit; | |
447 | struct listnode *node; | |
448 | ||
449 | if (CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) { | |
450 | for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) | |
451 | isis_if_ldp_sync_disable(circuit); | |
452 | ||
453 | UNSET_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE); | |
454 | ||
455 | UNSET_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN); | |
456 | area->ldp_sync_cmd.holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT; | |
457 | } | |
458 | } | |
459 | ||
460 | void isis_area_ldp_sync_set_holddown(struct isis_area *area, uint16_t holddown) | |
461 | { | |
462 | struct isis_circuit *circuit; | |
463 | struct listnode *node; | |
464 | ||
465 | if (holddown == LDP_IGP_SYNC_HOLDDOWN_DEFAULT) | |
466 | UNSET_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN); | |
467 | else | |
468 | SET_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN); | |
469 | ||
470 | area->ldp_sync_cmd.holddown = holddown; | |
471 | ||
472 | for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) | |
473 | isis_if_set_ldp_sync_holddown(circuit); | |
474 | } | |
475 | ||
476 | void isis_if_ldp_sync_enable(struct isis_circuit *circuit) | |
477 | { | |
478 | struct ldp_sync_info *ldp_sync_info = circuit->ldp_sync_info; | |
479 | struct isis_area *area = circuit->area; | |
1cbf96a8 | 480 | |
481 | /* called when setting LDP-SYNC at the global level: | |
bd4f51b1 | 482 | * specified on interface overrides global config |
1cbf96a8 | 483 | * if ptop link send msg to LDP indicating ldp-sync enabled |
bd4f51b1 | 484 | */ |
ec62fbaa | 485 | if (if_is_loopback(circuit->interface)) |
1cbf96a8 | 486 | return; |
487 | ||
b11f166c IR |
488 | if (circuit->interface->vrf->vrf_id != VRF_DEFAULT) |
489 | return; | |
490 | ||
11106e28 | 491 | ils_debug("%s: enable if %s", __func__, circuit->interface->name); |
1cbf96a8 | 492 | |
ec62fbaa IR |
493 | if (!CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) |
494 | return; | |
1cbf96a8 | 495 | |
ec62fbaa IR |
496 | /* config on interface, overrides global config. */ |
497 | if (CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG)) | |
498 | if (ldp_sync_info->enabled != LDP_IGP_SYNC_ENABLED) | |
499 | return; | |
1cbf96a8 | 500 | |
ec62fbaa IR |
501 | if (!CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN)) |
502 | ldp_sync_info->holddown = area->ldp_sync_cmd.holddown; | |
503 | ||
504 | if (circuit->circ_type == CIRCUIT_T_P2P | |
505 | || if_is_pointopoint(circuit->interface)) { | |
506 | ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP; | |
507 | isis_ldp_sync_state_req_msg(circuit); | |
508 | } else { | |
509 | ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED; | |
11106e28 | 510 | ils_debug("%s: Sync only runs on P2P links %s", __func__, |
ec62fbaa IR |
511 | circuit->interface->name); |
512 | } | |
513 | } | |
514 | ||
515 | void isis_if_ldp_sync_disable(struct isis_circuit *circuit) | |
516 | { | |
517 | struct ldp_sync_info *ldp_sync_info = circuit->ldp_sync_info; | |
518 | struct isis_area *area = circuit->area; | |
519 | ||
520 | /* Stop LDP-SYNC on this interface: | |
521 | * if holddown timer is running stop it | |
522 | * delete ldp instance on interface | |
523 | * restore metric | |
524 | */ | |
525 | if (if_is_loopback(circuit->interface)) | |
526 | return; | |
527 | ||
11106e28 | 528 | ils_debug("%s: remove if %s", __func__, circuit->interface->name); |
ec62fbaa IR |
529 | |
530 | if (!CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) | |
531 | return; | |
532 | ||
533 | THREAD_OFF(ldp_sync_info->t_holddown); | |
534 | ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED; | |
535 | isis_ldp_sync_set_if_metric(circuit, true); | |
1cbf96a8 | 536 | } |
537 | ||
538 | void isis_if_set_ldp_sync_holddown(struct isis_circuit *circuit) | |
539 | { | |
ec62fbaa IR |
540 | struct ldp_sync_info *ldp_sync_info = circuit->ldp_sync_info; |
541 | struct isis_area *area = circuit->area; | |
1cbf96a8 | 542 | |
543 | /* called when setting LDP-SYNC at the global level: | |
bd4f51b1 | 544 | * specified on interface overrides global config. |
1cbf96a8 | 545 | */ |
ec62fbaa | 546 | if (if_is_loopback(circuit->interface)) |
1cbf96a8 | 547 | return; |
548 | ||
1cbf96a8 | 549 | /* config on interface, overrides global config. */ |
550 | if (CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN)) | |
551 | return; | |
ec62fbaa IR |
552 | if (CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN)) |
553 | ldp_sync_info->holddown = area->ldp_sync_cmd.holddown; | |
1cbf96a8 | 554 | else |
555 | ldp_sync_info->holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT; | |
556 | } | |
557 | ||
1cbf96a8 | 558 | /* |
559 | * LDP-SYNC routines used by show commands. | |
560 | */ | |
561 | ||
562 | static void isis_circuit_ldp_sync_print_vty(struct isis_circuit *circuit, | |
563 | struct vty *vty) | |
564 | { | |
565 | struct ldp_sync_info *ldp_sync_info; | |
566 | const char *ldp_state; | |
567 | ||
568 | if (circuit->ldp_sync_info == NULL || | |
569 | if_is_loopback(circuit->interface)) | |
570 | return; | |
571 | ||
572 | ldp_sync_info = circuit->ldp_sync_info; | |
eb47c1be | 573 | vty_out(vty, "%-16s\n", circuit->interface->name); |
574 | if (circuit->state == C_STATE_CONF) { | |
575 | vty_out(vty, " Interface down\n"); | |
576 | return; | |
577 | } | |
578 | ||
1cbf96a8 | 579 | vty_out(vty, " LDP-IGP Synchronization enabled: %s\n", |
580 | ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED | |
581 | ? "yes" | |
582 | : "no"); | |
583 | vty_out(vty, " holddown timer in seconds: %u\n", | |
584 | ldp_sync_info->holddown); | |
585 | ||
586 | switch (ldp_sync_info->state) { | |
587 | case LDP_IGP_SYNC_STATE_REQUIRED_UP: | |
588 | vty_out(vty, " State: Sync achieved\n"); | |
589 | break; | |
590 | case LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP: | |
591 | if (ldp_sync_info->t_holddown != NULL) { | |
592 | struct timeval remain = thread_timer_remain( | |
593 | ldp_sync_info->t_holddown); | |
594 | vty_out(vty, | |
595 | " Holddown timer is running %lld.%03lld remaining\n", | |
596 | (long long)remain.tv_sec, | |
597 | (long long)remain.tv_usec/1000); | |
598 | ||
599 | vty_out(vty, " State: Holding down until Sync\n"); | |
600 | } else | |
601 | vty_out(vty, " State: Sync not achieved\n"); | |
602 | break; | |
603 | case LDP_IGP_SYNC_STATE_NOT_REQUIRED: | |
604 | default: | |
605 | if ((circuit->circ_type != CIRCUIT_T_P2P && | |
606 | !if_is_pointopoint(circuit->interface)) && | |
607 | circuit->circ_type != CIRCUIT_T_UNKNOWN) | |
608 | ldp_state = "Sync not required: non-p2p link"; | |
609 | else | |
610 | ldp_state = "Sync not required"; | |
611 | vty_out(vty, " State: %s\n", ldp_state); | |
612 | break; | |
613 | } | |
614 | } | |
615 | ||
616 | DEFUN (show_isis_mpls_ldp_interface, | |
617 | show_isis_mpls_ldp_interface_cmd, | |
618 | "show " PROTO_NAME " mpls ldp-sync [interface <INTERFACE|all>]", | |
619 | SHOW_STR | |
620 | PROTO_HELP | |
621 | MPLS_STR | |
622 | "LDP-IGP Sync information\n" | |
31011d9c IR |
623 | "Interface information\n" |
624 | "Interface name\n" | |
625 | "All interfaces\n") | |
1cbf96a8 | 626 | { |
627 | char *ifname = NULL; | |
628 | int idx_intf = 0; | |
629 | struct listnode *anode, *cnode; | |
630 | struct isis_area *area; | |
631 | struct isis_circuit *circuit; | |
632 | struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); | |
eb47c1be | 633 | bool found = false; |
1cbf96a8 | 634 | |
635 | if (!isis) { | |
636 | vty_out(vty, "IS-IS Routing Process not enabled\n"); | |
637 | return CMD_SUCCESS; | |
638 | } | |
639 | ||
1cbf96a8 | 640 | if (argv_find(argv, argc, "INTERFACE", &idx_intf)) |
641 | ifname = argv[idx_intf]->arg; | |
642 | ||
643 | for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) { | |
644 | for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit)) | |
645 | if (!ifname) | |
646 | isis_circuit_ldp_sync_print_vty(circuit, vty); | |
eb47c1be | 647 | else if (strcmp(circuit->interface->name, ifname) |
648 | == 0) { | |
1cbf96a8 | 649 | isis_circuit_ldp_sync_print_vty(circuit, vty); |
eb47c1be | 650 | found = true; |
651 | } | |
1cbf96a8 | 652 | } |
653 | ||
eb47c1be | 654 | if (found == false && ifname) |
655 | vty_out(vty, "%-16s\n ISIS not enabled\n", ifname); | |
656 | ||
1cbf96a8 | 657 | return CMD_SUCCESS; |
658 | } | |
659 | ||
660 | void isis_ldp_sync_init(void) | |
661 | { | |
662 | ||
663 | /* "show ip isis mpls ldp interface" commands. */ | |
664 | install_element(VIEW_NODE, &show_isis_mpls_ldp_interface_cmd); | |
665 | ||
666 | /* register for adjacency state changes */ | |
667 | hook_register(isis_adj_state_change_hook, | |
668 | isis_ldp_sync_adj_state_change); | |
669 | } |