]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_ldp_sync.c
doc: Add `show ipv6 rpf X:X::X:X` command to docs
[mirror_frr.git] / isisd / isis_ldp_sync.c
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;
68
69 /* lookup circuit */
70 ifp = if_lookup_by_index(state.ifindex, VRF_DEFAULT);
71 if (ifp == NULL)
72 return 0;
73
74 circuit = ifp->info;
75 if (circuit == NULL)
76 return 0;
77
78 /* if isis is not enabled or LDP-SYNC is not configured ignore */
79 area = circuit->area;
80 if (area == NULL
81 || !CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
82 return 0;
83
84 /* received ldp-sync interface state from LDP */
85 ils_debug("%s: rcvd %s from LDP if %s", __func__,
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;
98 struct listnode *anode, *cnode;
99 struct isis_circuit *circuit;
100 struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
101
102 /* if isis is not enabled ignore */
103 if (!isis)
104 return 0;
105
106 if (announce.proto != ZEBRA_ROUTE_LDP)
107 return 0;
108
109 ils_debug("%s: rcvd announce from LDP", __func__);
110
111 /* LDP just started up:
112 * set cost to LSInfinity
113 * send request to LDP for LDP-SYNC state for each interface
114 */
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))
120 isis_ldp_sync_if_start(circuit, true);
121 }
122
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
131 ils_debug("%s: send state request to LDP for %s", __func__, ifp->name);
132
133 memset(&request, 0, sizeof(request));
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 */
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) {
161 ils_debug("%s: start on if %s state: %s", __func__,
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;
186
187 THREAD_OFF(ldp_sync_info->t_holddown);
188
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
199 /* LDP client close detected:
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) {
207 THREAD_OFF(ldp_sync_info->t_holddown);
208 ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
209 isis_ldp_sync_set_if_metric(circuit, true);
210 }
211 }
212
213 static int isis_ldp_sync_adj_state_change(struct isis_adjacency *adj)
214 {
215 struct isis_circuit *circuit = adj->circuit;
216 struct ldp_sync_info *ldp_sync_info = circuit->ldp_sync_info;
217 struct isis_area *area = circuit->area;
218
219 if (!CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)
220 || circuit->interface->vrf->vrf_id != VRF_DEFAULT
221 || if_is_loopback(circuit->interface))
222 return 0;
223
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
248 ils_debug("%s: down on if %s", __func__,
249 circuit->interface->name);
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;
260 struct isis_area *area = circuit->area;
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 */
267 if (area && CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)
268 && ldp_sync_info != NULL) {
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];
303 circuit->te_metric[0] =
304 ISIS_WIDE_METRIC_INFINITY;
305 } else {
306 ldp_sync_info->metric[0] = circuit->metric[0];
307 circuit->metric[0] =
308 ISIS_NARROW_METRIC_INFINITY;
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];
315 circuit->te_metric[1] =
316 ISIS_WIDE_METRIC_INFINITY;
317 } else {
318 ldp_sync_info->metric[1] = circuit->metric[1];
319 circuit->metric[1] =
320 ISIS_NARROW_METRIC_INFINITY;
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 */
347 static void isis_ldp_sync_holddown_timer(struct thread *thread)
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)
358 return;
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
365 ils_debug("%s: holddown timer expired for %s state:sync achieved",
366 __func__, circuit->interface->name);
367
368 isis_ldp_sync_set_if_metric(circuit, true);
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
386 ils_debug("%s: start holddown timer for %s time %d", __func__,
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
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;
400 struct listnode *anode, *cnode;
401 struct isis_circuit *circuit;
402 struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
403
404 /* if isis is not enabled ignore */
405 if (!isis)
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 */
416 zlog_err("%s: LDP down", __func__);
417
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))
423 isis_ldp_sync_ldp_fail(circuit);
424 }
425 }
426
427 /*
428 * LDP-SYNC routes used by set commands.
429 */
430
431 void isis_area_ldp_sync_enable(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 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;
480
481 /* called when setting LDP-SYNC at the global level:
482 * specified on interface overrides global config
483 * if ptop link send msg to LDP indicating ldp-sync enabled
484 */
485 if (if_is_loopback(circuit->interface))
486 return;
487
488 if (circuit->interface->vrf->vrf_id != VRF_DEFAULT)
489 return;
490
491 ils_debug("%s: enable if %s", __func__, circuit->interface->name);
492
493 if (!CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
494 return;
495
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;
500
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;
510 ils_debug("%s: Sync only runs on P2P links %s", __func__,
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
528 ils_debug("%s: remove if %s", __func__, circuit->interface->name);
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);
536 }
537
538 void isis_if_set_ldp_sync_holddown(struct isis_circuit *circuit)
539 {
540 struct ldp_sync_info *ldp_sync_info = circuit->ldp_sync_info;
541 struct isis_area *area = circuit->area;
542
543 /* called when setting LDP-SYNC at the global level:
544 * specified on interface overrides global config.
545 */
546 if (if_is_loopback(circuit->interface))
547 return;
548
549 /* config on interface, overrides global config. */
550 if (CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN))
551 return;
552 if (CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN))
553 ldp_sync_info->holddown = area->ldp_sync_cmd.holddown;
554 else
555 ldp_sync_info->holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT;
556 }
557
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;
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
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"
623 "Interface information\n"
624 "Interface name\n"
625 "All interfaces\n")
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);
633 bool found = false;
634
635 if (!isis) {
636 vty_out(vty, "IS-IS Routing Process not enabled\n");
637 return CMD_SUCCESS;
638 }
639
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);
647 else if (strcmp(circuit->interface->name, ifname)
648 == 0) {
649 isis_circuit_ldp_sync_print_vty(circuit, vty);
650 found = true;
651 }
652 }
653
654 if (found == false && ifname)
655 vty_out(vty, "%-16s\n ISIS not enabled\n", ifname);
656
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 }