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