]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_ldp_sync.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[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 "thread.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 THREAD_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 THREAD_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 thread *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 = THREAD_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 thread_add_timer(master, isis_ldp_sync_holddown_timer,
377 circuit, ldp_sync_info->holddown,
378 &ldp_sync_info->t_holddown);
379 }
380
381 /*
382 * LDP-SYNC handle client close routine
383 */
384 void isis_ldp_sync_handle_client_close(struct zapi_client_close_info *info)
385 {
386 struct isis_area *area;
387 struct listnode *anode, *cnode;
388 struct isis_circuit *circuit;
389 struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
390
391 /* if isis is not enabled ignore */
392 if (!isis)
393 return;
394
395 /* Check if the LDP main client session closed */
396 if (info->proto != ZEBRA_ROUTE_LDP || info->session_id == 0)
397 return;
398
399 /* Handle the zebra notification that the LDP client session closed.
400 * set cost to LSInfinity
401 * send request to LDP for LDP-SYNC state for each interface
402 */
403 zlog_err("%s: LDP down", __func__);
404
405 for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) {
406 if (!CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
407 continue;
408
409 for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit))
410 isis_ldp_sync_ldp_fail(circuit);
411 }
412 }
413
414 /*
415 * LDP-SYNC routes used by set commands.
416 */
417
418 void isis_area_ldp_sync_enable(struct isis_area *area)
419 {
420 struct isis_circuit *circuit;
421 struct listnode *node;
422
423 if (!CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) {
424 SET_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE);
425
426 for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit))
427 isis_if_ldp_sync_enable(circuit);
428 }
429 }
430
431 void isis_area_ldp_sync_disable(struct isis_area *area)
432 {
433 struct isis_circuit *circuit;
434 struct listnode *node;
435
436 if (CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) {
437 for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit))
438 isis_if_ldp_sync_disable(circuit);
439
440 UNSET_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE);
441
442 UNSET_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN);
443 area->ldp_sync_cmd.holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT;
444 }
445 }
446
447 void isis_area_ldp_sync_set_holddown(struct isis_area *area, uint16_t holddown)
448 {
449 struct isis_circuit *circuit;
450 struct listnode *node;
451
452 if (holddown == LDP_IGP_SYNC_HOLDDOWN_DEFAULT)
453 UNSET_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN);
454 else
455 SET_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN);
456
457 area->ldp_sync_cmd.holddown = holddown;
458
459 for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit))
460 isis_if_set_ldp_sync_holddown(circuit);
461 }
462
463 void isis_if_ldp_sync_enable(struct isis_circuit *circuit)
464 {
465 struct ldp_sync_info *ldp_sync_info = circuit->ldp_sync_info;
466 struct isis_area *area = circuit->area;
467
468 /* called when setting LDP-SYNC at the global level:
469 * specified on interface overrides global config
470 * if ptop link send msg to LDP indicating ldp-sync enabled
471 */
472 if (if_is_loopback(circuit->interface))
473 return;
474
475 if (circuit->interface->vrf->vrf_id != VRF_DEFAULT)
476 return;
477
478 ils_debug("%s: enable if %s", __func__, circuit->interface->name);
479
480 if (!CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
481 return;
482
483 /* config on interface, overrides global config. */
484 if (CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG))
485 if (ldp_sync_info->enabled != LDP_IGP_SYNC_ENABLED)
486 return;
487
488 if (!CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN))
489 ldp_sync_info->holddown = area->ldp_sync_cmd.holddown;
490
491 if (circuit->circ_type == CIRCUIT_T_P2P
492 || if_is_pointopoint(circuit->interface)) {
493 ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
494 isis_ldp_sync_state_req_msg(circuit);
495 } else {
496 ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED;
497 ils_debug("%s: Sync only runs on P2P links %s", __func__,
498 circuit->interface->name);
499 }
500 }
501
502 void isis_if_ldp_sync_disable(struct isis_circuit *circuit)
503 {
504 struct ldp_sync_info *ldp_sync_info = circuit->ldp_sync_info;
505 struct isis_area *area = circuit->area;
506
507 /* Stop LDP-SYNC on this interface:
508 * if holddown timer is running stop it
509 * delete ldp instance on interface
510 * restore metric
511 */
512 if (if_is_loopback(circuit->interface))
513 return;
514
515 ils_debug("%s: remove if %s", __func__, circuit->interface->name);
516
517 if (!CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
518 return;
519
520 THREAD_OFF(ldp_sync_info->t_holddown);
521 ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED;
522 isis_ldp_sync_set_if_metric(circuit, true);
523 }
524
525 void isis_if_set_ldp_sync_holddown(struct isis_circuit *circuit)
526 {
527 struct ldp_sync_info *ldp_sync_info = circuit->ldp_sync_info;
528 struct isis_area *area = circuit->area;
529
530 /* called when setting LDP-SYNC at the global level:
531 * specified on interface overrides global config.
532 */
533 if (if_is_loopback(circuit->interface))
534 return;
535
536 /* config on interface, overrides global config. */
537 if (CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN))
538 return;
539 if (CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN))
540 ldp_sync_info->holddown = area->ldp_sync_cmd.holddown;
541 else
542 ldp_sync_info->holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT;
543 }
544
545 /*
546 * LDP-SYNC routines used by show commands.
547 */
548
549 static void isis_circuit_ldp_sync_print_vty(struct isis_circuit *circuit,
550 struct vty *vty)
551 {
552 struct ldp_sync_info *ldp_sync_info;
553 const char *ldp_state;
554
555 if (circuit->ldp_sync_info == NULL ||
556 if_is_loopback(circuit->interface))
557 return;
558
559 ldp_sync_info = circuit->ldp_sync_info;
560 vty_out(vty, "%-16s\n", circuit->interface->name);
561 if (circuit->state == C_STATE_CONF) {
562 vty_out(vty, " Interface down\n");
563 return;
564 }
565
566 vty_out(vty, " LDP-IGP Synchronization enabled: %s\n",
567 ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED
568 ? "yes"
569 : "no");
570 vty_out(vty, " holddown timer in seconds: %u\n",
571 ldp_sync_info->holddown);
572
573 switch (ldp_sync_info->state) {
574 case LDP_IGP_SYNC_STATE_REQUIRED_UP:
575 vty_out(vty, " State: Sync achieved\n");
576 break;
577 case LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP:
578 if (ldp_sync_info->t_holddown != NULL) {
579 struct timeval remain = thread_timer_remain(
580 ldp_sync_info->t_holddown);
581 vty_out(vty,
582 " Holddown timer is running %lld.%03lld remaining\n",
583 (long long)remain.tv_sec,
584 (long long)remain.tv_usec/1000);
585
586 vty_out(vty, " State: Holding down until Sync\n");
587 } else
588 vty_out(vty, " State: Sync not achieved\n");
589 break;
590 case LDP_IGP_SYNC_STATE_NOT_REQUIRED:
591 default:
592 if ((circuit->circ_type != CIRCUIT_T_P2P &&
593 !if_is_pointopoint(circuit->interface)) &&
594 circuit->circ_type != CIRCUIT_T_UNKNOWN)
595 ldp_state = "Sync not required: non-p2p link";
596 else
597 ldp_state = "Sync not required";
598 vty_out(vty, " State: %s\n", ldp_state);
599 break;
600 }
601 }
602
603 DEFUN (show_isis_mpls_ldp_interface,
604 show_isis_mpls_ldp_interface_cmd,
605 "show " PROTO_NAME " mpls ldp-sync [interface <INTERFACE|all>]",
606 SHOW_STR
607 PROTO_HELP
608 MPLS_STR
609 "LDP-IGP Sync information\n"
610 "Interface information\n"
611 "Interface name\n"
612 "All interfaces\n")
613 {
614 char *ifname = NULL;
615 int idx_intf = 0;
616 struct listnode *anode, *cnode;
617 struct isis_area *area;
618 struct isis_circuit *circuit;
619 struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
620 bool found = false;
621
622 if (!isis) {
623 vty_out(vty, "IS-IS Routing Process not enabled\n");
624 return CMD_SUCCESS;
625 }
626
627 if (argv_find(argv, argc, "INTERFACE", &idx_intf))
628 ifname = argv[idx_intf]->arg;
629
630 for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) {
631 for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit))
632 if (!ifname)
633 isis_circuit_ldp_sync_print_vty(circuit, vty);
634 else if (strcmp(circuit->interface->name, ifname)
635 == 0) {
636 isis_circuit_ldp_sync_print_vty(circuit, vty);
637 found = true;
638 }
639 }
640
641 if (found == false && ifname)
642 vty_out(vty, "%-16s\n ISIS not enabled\n", ifname);
643
644 return CMD_SUCCESS;
645 }
646
647 void isis_ldp_sync_init(void)
648 {
649
650 /* "show ip isis mpls ldp interface" commands. */
651 install_element(VIEW_NODE, &show_isis_mpls_ldp_interface_cmd);
652
653 /* register for adjacency state changes */
654 hook_register(isis_adj_state_change_hook,
655 isis_ldp_sync_adj_state_change);
656 }