]> git.puffer.fish Git - matthieu/frr.git/commitdiff
isisd: ldp-igp-sync feature: adding isis support
authorlynne <lynne@voltanet.io>
Wed, 22 Jul 2020 18:32:35 +0000 (14:32 -0400)
committerlynne <lynne@voltanet.io>
Wed, 9 Sep 2020 18:38:44 +0000 (14:38 -0400)
Signed-off-by: Lynne Morrison <lynne@voltanet.io>
Signed-off-by: Karen Schoener <karen@voltanet.io>
14 files changed:
isisd/isis_circuit.c
isisd/isis_circuit.h
isisd/isis_cli.c
isisd/isis_ldp_sync.c [new file with mode: 0644]
isisd/isis_ldp_sync.h [new file with mode: 0644]
isisd/isis_main.c
isisd/isis_nb.c
isisd/isis_nb.h
isisd/isis_nb_config.c
isisd/isis_zebra.c
isisd/isisd.c
isisd/isisd.h
isisd/subdir.am
yang/frr-isisd.yang

index 985e07820f5ee51dddc9f8ceeb94ba5f5ed10d61..80d70095c4addf4d297c2892c7d103d1e71e2f88 100644 (file)
@@ -59,6 +59,7 @@
 #include "isisd/isis_errors.h"
 #include "isisd/isis_tx_queue.h"
 #include "isisd/isis_nb.h"
+#include "isisd/isis_ldp_sync.h"
 
 DEFINE_QOBJ_TYPE(isis_circuit)
 
@@ -1276,6 +1277,7 @@ struct isis_circuit *isis_circuit_create(struct isis_area *area,
        isis_circuit_if_bind(circuit, ifp);
        if (circuit->area->mta && circuit->area->mta->status)
                isis_link_params_update(circuit, ifp);
+
        return circuit;
 }
 
@@ -1346,11 +1348,16 @@ ferr_r isis_circuit_metric_set(struct isis_circuit *circuit, int level,
                return ferr_cfg_invalid("metric %d too large for narrow metric",
                                        metric);
 
-       circuit->te_metric[level - 1] = metric;
-       circuit->metric[level - 1] = metric;
-
-       if (circuit->area)
-               lsp_regenerate_schedule(circuit->area, level, 0);
+       /* inform ldp-sync of metric change
+         *   if ldp-sync is running need to save metric
+         *   and restore new values after ldp-sync completion.
+        */
+       if (isis_ldp_sync_if_metric_config(circuit, level, metric)) {
+               circuit->te_metric[level - 1] = metric;
+               circuit->metric[level - 1] = metric;
+               if (circuit->area)
+                       lsp_regenerate_schedule(circuit->area, level, 0);
+       }
        return ferr_ok();
 }
 
index da358f411b01694c3cb231fc63df145d8b18b8cc..5766d1962f277eba5000601c4f2581647ff4b182 100644 (file)
@@ -139,6 +139,7 @@ struct isis_circuit {
        uint8_t flags;
        bool disable_threeway_adj;
        struct bfd_info *bfd_info;
+       struct ldp_sync_info *ldp_sync_info;
        /*
         * Counters as in 10589--11.2.5.9
         */
index 4d0275800342b8c3c0641a87fd61fe912aab4d62..6b4df780941861d747ede4e63a7515fb3e195360 100644 (file)
@@ -2320,6 +2320,178 @@ void cli_show_isis_log_adjacency(struct vty *vty, struct lyd_node *dnode,
        vty_out(vty, " log-adjacency-changes\n");
 }
 
+/*
+ * XPath: /frr-isisd:isis/instance/mpls/ldp-sync
+ */
+DEFPY(isis_mpls_ldp_sync, isis_mpls_ldp_sync_cmd, "mpls ldp-sync",
+      MPLS_STR MPLS_LDP_SYNC_STR)
+{
+       nb_cli_enqueue_change(vty, "./mpls/ldp-sync", NB_OP_CREATE, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(no_isis_mpls_ldp_sync, no_isis_mpls_ldp_sync_cmd, "no mpls ldp-sync",
+      NO_STR MPLS_STR NO_MPLS_LDP_SYNC_STR)
+{
+       nb_cli_enqueue_change(vty, "./mpls/ldp-sync", NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+void cli_show_isis_mpls_ldp_sync(struct vty *vty, struct lyd_node *dnode,
+                                bool show_defaults)
+{
+       vty_out(vty, " mpls ldp-sync\n");
+}
+
+DEFPY(isis_mpls_ldp_sync_holddown, isis_mpls_ldp_sync_holddown_cmd,
+      "mpls ldp-sync holddown (0-10000)",
+      MPLS_STR MPLS_LDP_SYNC_STR
+      "Time to wait for LDP-SYNC to occur before restoring interface metric\n"
+      "Time in seconds\n")
+{
+       nb_cli_enqueue_change(vty, "./mpls/ldp-sync/holddown", NB_OP_MODIFY,
+                             holddown_str);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(no_isis_mpls_ldp_sync_holddown, no_isis_mpls_ldp_sync_holddown_cmd,
+      "no mpls ldp-sync holddown [<(1-10000)>]",
+      NO_STR MPLS_STR MPLS_LDP_SYNC_STR NO_MPLS_LDP_SYNC_HOLDDOWN_STR)
+{
+       nb_cli_enqueue_change(vty, "./mpls/ldp-sync/holddown", NB_OP_DESTROY,
+                             NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+void cli_show_isis_mpls_ldp_sync_holddown(struct vty *vty,
+                                         struct lyd_node *dnode,
+                                         bool show_defaults)
+{
+       vty_out(vty, " mpls ldp-sync holddown %s\n",
+               yang_dnode_get_string(dnode, NULL));
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/mpls/ldp-sync
+ */
+DEFPY(isis_mpls_if_ldp_sync, isis_mpls_if_ldp_sync_cmd,
+      "[no] isis mpls ldp-sync",
+      NO_STR "IS-IS routing protocol\n" MPLS_STR MPLS_LDP_SYNC_STR)
+{
+       const struct lyd_node *dnode;
+       struct interface *ifp;
+
+       dnode = yang_dnode_get(vty->candidate_config->dnode,
+                              "%s/frr-isisd:isis", VTY_CURR_XPATH);
+       if (dnode == NULL) {
+               vty_out(vty, "ISIS is not enabled on this circuit\n");
+               return CMD_SUCCESS;
+       }
+
+       ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
+       if (if_is_loopback(ifp)) {
+               vty_out(vty, "ldp-sync does not run on loopback interface\n");
+               return CMD_SUCCESS;
+       }
+
+       if (ifp->vrf_id != VRF_DEFAULT) {
+               vty_out(vty, "ldp-sync only runs on DEFAULT VRF\n");
+               return CMD_SUCCESS;
+       }
+
+       nb_cli_enqueue_change(vty, "./frr-isisd:isis/mpls/ldp-sync",
+                             NB_OP_MODIFY, no ? "false" : "true");
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+
+void cli_show_isis_mpls_if_ldp_sync(struct vty *vty, struct lyd_node *dnode,
+                                   bool show_defaults)
+{
+       if (!yang_dnode_get_bool(dnode, NULL))
+               vty_out(vty, " no");
+
+       vty_out(vty, " isis mpls ldp-sync\n");
+}
+
+DEFPY(isis_mpls_if_ldp_sync_holddown, isis_mpls_if_ldp_sync_holddown_cmd,
+      "isis mpls ldp-sync holddown (0-10000)",
+      "IS-IS routing protocol\n" MPLS_STR MPLS_LDP_SYNC_STR
+      "Time to wait for LDP-SYNC to occur before restoring interface metric\n"
+      "Time in seconds\n")
+{
+       const struct lyd_node *dnode;
+       struct interface *ifp;
+
+       dnode = yang_dnode_get(vty->candidate_config->dnode,
+                              "%s/frr-isisd:isis", VTY_CURR_XPATH);
+       if (dnode == NULL) {
+               vty_out(vty, "ISIS is not enabled on this circuit\n");
+               return CMD_SUCCESS;
+       }
+
+       ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
+       if (if_is_loopback(ifp)) {
+               vty_out(vty, "ldp-sync does not run on loopback interface\n");
+               return CMD_SUCCESS;
+       }
+
+       if (ifp->vrf_id != VRF_DEFAULT) {
+               vty_out(vty, "ldp-sync only runs on DEFAULT VRF\n");
+               return CMD_SUCCESS;
+       }
+
+       nb_cli_enqueue_change(vty, "./frr-isisd:isis/mpls/holddown",
+                             NB_OP_MODIFY, holddown_str);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(no_isis_mpls_if_ldp_sync_holddown, no_isis_mpls_if_ldp_sync_holddown_cmd,
+      "no isis mpls ldp-sync holddown [<(1-10000)>]",
+      NO_STR "IS-IS routing protocol\n" MPLS_STR NO_MPLS_LDP_SYNC_STR
+             NO_MPLS_LDP_SYNC_HOLDDOWN_STR)
+{
+       const struct lyd_node *dnode;
+       struct interface *ifp;
+
+       dnode = yang_dnode_get(vty->candidate_config->dnode,
+                              "%s/frr-isisd:isis", VTY_CURR_XPATH);
+       if (dnode == NULL) {
+               vty_out(vty, "ISIS is not enabled on this circuit\n");
+               return CMD_SUCCESS;
+       }
+
+       ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
+       if (if_is_loopback(ifp)) {
+               vty_out(vty, "ldp-sync does not run on loopback interface\n");
+               return CMD_SUCCESS;
+       }
+
+       if (ifp->vrf_id != VRF_DEFAULT) {
+               vty_out(vty, "ldp-sync only runs on DEFAULT VRF\n");
+               return CMD_SUCCESS;
+       }
+
+       nb_cli_enqueue_change(vty, "./frr-isisd:isis/mpls/holddown",
+                             NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+void cli_show_isis_mpls_if_ldp_sync_holddown(struct vty *vty,
+                                            struct lyd_node *dnode,
+                                            bool show_defaults)
+{
+       vty_out(vty, " isis mpls ldp-sync holddown %s\n",
+               yang_dnode_get_string(dnode, NULL));
+}
+
 void isis_cli_init(void)
 {
        install_element(CONFIG_NODE, &router_isis_cmd);
@@ -2423,6 +2595,14 @@ void isis_cli_init(void)
        install_element(INTERFACE_NODE, &no_isis_priority_cmd);
 
        install_element(ISIS_NODE, &log_adj_changes_cmd);
+
+       install_element(ISIS_NODE, &isis_mpls_ldp_sync_cmd);
+       install_element(ISIS_NODE, &no_isis_mpls_ldp_sync_cmd);
+       install_element(ISIS_NODE, &isis_mpls_ldp_sync_holddown_cmd);
+       install_element(ISIS_NODE, &no_isis_mpls_ldp_sync_holddown_cmd);
+       install_element(INTERFACE_NODE, &isis_mpls_if_ldp_sync_cmd);
+       install_element(INTERFACE_NODE, &isis_mpls_if_ldp_sync_holddown_cmd);
+       install_element(INTERFACE_NODE, &no_isis_mpls_if_ldp_sync_holddown_cmd);
 }
 
 #endif /* ifndef FABRICD */
diff --git a/isisd/isis_ldp_sync.c b/isisd/isis_ldp_sync.c
new file mode 100644 (file)
index 0000000..42928e0
--- /dev/null
@@ -0,0 +1,788 @@
+/**
+ * isis_ldp_sync.c: ISIS LDP-IGP Sync  handling routines
+ * Copyright (C) 2020 Volta Networks, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+#include <string.h>
+
+#include "monotime.h"
+#include "memory.h"
+#include "thread.h"
+#include "prefix.h"
+#include "table.h"
+#include "vty.h"
+#include "command.h"
+#include "plist.h"
+#include "log.h"
+#include "zclient.h"
+#include <lib/json.h>
+#include "defaults.h"
+#include "ldp_sync.h"
+
+#include "isisd/isis_constants.h"
+#include "isisd/isis_common.h"
+#include "isisd/isis_flags.h"
+#include "isisd/isis_circuit.h"
+#include "isisd/isis_lsp.h"
+#include "isisd/isis_pdu.h"
+#include "isisd/isis_network.h"
+#include "isisd/isis_misc.h"
+#include "isisd/isis_constants.h"
+#include "isisd/isis_adjacency.h"
+#include "isisd/isis_dr.h"
+#include "isisd/isisd.h"
+#include "isisd/isis_csm.h"
+#include "isisd/isis_events.h"
+#include "isisd/isis_te.h"
+#include "isisd/isis_mt.h"
+#include "isisd/isis_errors.h"
+#include "isisd/isis_tx_queue.h"
+#include "isisd/isis_nb.h"
+#include "isisd/isis_ldp_sync.h"
+
+extern struct zclient *zclient;
+
+/*
+ * LDP-SYNC msg between IGP and LDP
+ */
+int isis_ldp_sync_state_update(struct ldp_igp_sync_if_state state)
+{
+       struct interface *ifp;
+       struct isis_circuit *circuit = NULL;
+       struct isis_area *area;
+       struct listnode *node;
+       struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+       /* if isis is not enabled or LDP-SYNC is not configured ignore */
+       if (!isis ||
+           !CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
+               return 0;
+
+       /* lookup circuit */
+       ifp = if_lookup_by_index(state.ifindex, VRF_DEFAULT);
+       if (ifp == NULL)
+               return 0;
+
+       for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
+               circuit = circuit_lookup_by_ifp(ifp, area->circuit_list);
+               if (circuit != NULL)
+                       break;
+       }
+
+       /* if isis is not enabled or LDP-SYNC is not configured ignore */
+       if (circuit == NULL ||
+           !CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
+               return 0;
+
+       /* received ldp-sync interface state from LDP */
+       ils_debug("ldp_sync: rcvd %s from LDP if %s",
+                 state.sync_start ? "sync-start" : "sync-complete", ifp->name);
+       if (state.sync_start)
+               isis_ldp_sync_if_start(circuit, false);
+       else
+               isis_ldp_sync_if_complete(circuit);
+
+       return 0;
+}
+
+int isis_ldp_sync_announce_update(struct ldp_igp_sync_announce announce)
+{
+       struct isis_area *area;
+       struct listnode *node;
+       struct vrf *vrf;
+       struct interface *ifp;
+       struct isis_circuit *circuit;
+       struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+       /* if isis is not enabled or LDP-SYNC is not configured ignore */
+       if (!isis ||
+           !CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
+               return 0;
+
+       if (announce.proto != ZEBRA_ROUTE_LDP)
+               return 0;
+
+       ils_debug("ldp_sync: rcvd announce from LDP");
+
+       /* LDP just started up:
+        *  set cost to LSInfinity
+        *  send request to LDP for LDP-SYNC state for each interface
+        *  start hello timer
+        */
+       vrf = vrf_lookup_by_id(VRF_DEFAULT);
+       FOR_ALL_INTERFACES (vrf, ifp) {
+               for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
+                       circuit = circuit_lookup_by_ifp(ifp,
+                               area->circuit_list);
+                       if (circuit == NULL)
+                               continue;
+                       isis_ldp_sync_if_start(circuit, true);
+               }
+       }
+
+       THREAD_TIMER_OFF(isis->ldp_sync_cmd.t_hello);
+       isis->ldp_sync_cmd.t_hello = NULL;
+       isis->ldp_sync_cmd.sequence = 0;
+       isis_ldp_sync_hello_timer_add();
+
+       return 0;
+}
+
+int isis_ldp_sync_hello_update(struct ldp_igp_sync_hello hello)
+{
+       struct isis_area *area;
+       struct listnode *node;
+       struct vrf *vrf;
+       struct interface *ifp;
+       struct isis_circuit *circuit;
+       struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+       /* if isis is not enabled or LDP-SYNC is not configured ignore */
+       if (!isis ||
+           !CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
+               return 0;
+
+       if (hello.proto != ZEBRA_ROUTE_LDP)
+               return 0;
+
+       /* Received Hello from LDP:
+        *  if current sequence number is greater than received hello
+        *  sequence number then assume LDP restarted
+        *  set cost to LSInfinity
+        *  send request to LDP for LDP-SYNC state for each interface
+        *  else all is fine just restart hello timer
+        */
+       if (hello.sequence == 0)
+               /* rolled over */
+               isis->ldp_sync_cmd.sequence = 0;
+
+       if (isis->ldp_sync_cmd.sequence > hello.sequence) {
+               zlog_err("ldp_sync: LDP restarted");
+
+               vrf = vrf_lookup_by_id(VRF_DEFAULT);
+               FOR_ALL_INTERFACES (vrf, ifp) {
+                       for (ALL_LIST_ELEMENTS_RO(isis->area_list, node,
+                                                 area)) {
+                               circuit = circuit_lookup_by_ifp(ifp,
+                                       area->circuit_list);
+                               if (circuit == NULL)
+                                       continue;
+                               isis_ldp_sync_if_start(circuit, true);
+                       }
+               }
+       } else {
+               THREAD_TIMER_OFF(isis->ldp_sync_cmd.t_hello);
+               isis_ldp_sync_hello_timer_add();
+       }
+       isis->ldp_sync_cmd.sequence = hello.sequence;
+
+       return 0;
+}
+
+void isis_ldp_sync_state_req_msg(struct isis_circuit *circuit)
+{
+       struct ldp_igp_sync_if_state_req request;
+       struct interface *ifp = circuit->interface;
+
+       ils_debug("ldp_sync: send state request to LDP for %s",
+                 ifp->name);
+
+       strlcpy(request.name, ifp->name, sizeof(ifp->name));
+       request.proto = LDP_IGP_SYNC_IF_STATE_REQUEST;
+       request.ifindex = ifp->ifindex;
+
+       zclient_send_opaque(zclient, LDP_IGP_SYNC_IF_STATE_REQUEST,
+               (uint8_t *)&request, sizeof(request));
+}
+
+/*
+ * LDP-SYNC general interface routines
+ */
+void isis_ldp_sync_if_init(struct isis_circuit *circuit, struct isis *isis)
+{
+       struct ldp_sync_info *ldp_sync_info;
+       struct interface *ifp = circuit->interface;
+
+       /* called when ISIS is configured on an interface
+        *  if LDP-IGP Sync is configured globally set state
+        *  and if ptop interface LDP LDP-SYNC is enabled
+        */
+       ils_debug("ldp_sync: init if %s ", ifp->name);
+       if (circuit->ldp_sync_info == NULL)
+               circuit->ldp_sync_info = ldp_sync_info_create();
+       ldp_sync_info = circuit->ldp_sync_info;
+
+       /* specifed on interface overrides global config. */
+       if (!CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN))
+               ldp_sync_info->holddown = isis->ldp_sync_cmd.holddown;
+
+       if (!CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG))
+               ldp_sync_info->enabled = LDP_IGP_SYNC_ENABLED;
+
+       if ((circuit->circ_type == CIRCUIT_T_P2P || if_is_pointopoint(ifp)) &&
+           ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED)
+               ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
+}
+
+void isis_ldp_sync_if_start(struct isis_circuit *circuit,
+       bool send_state_req)
+{
+       struct ldp_sync_info *ldp_sync_info;
+
+       ldp_sync_info = circuit->ldp_sync_info;
+
+       /* Start LDP-SYNC on this interface:
+        *  set cost of interface to LSInfinity so traffic will use different
+        *  interface until LDP has learned all labels from peer
+        *  start holddown timer if configured
+        *  send msg to LDP to get LDP-SYNC state
+        */
+       if (ldp_sync_info &&
+           ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED &&
+           ldp_sync_info->state != LDP_IGP_SYNC_STATE_NOT_REQUIRED) {
+               ils_debug("ldp_sync: start on if %s state: %s",
+                         circuit->interface->name, "Holding down until Sync");
+               ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
+               isis_ldp_sync_set_if_metric(circuit, true);
+               isis_ldp_sync_holddown_timer_add(circuit);
+
+               if (send_state_req)
+                       isis_ldp_sync_state_req_msg(circuit);
+       }
+}
+
+void isis_ldp_sync_if_complete(struct isis_circuit *circuit)
+{
+       struct ldp_sync_info *ldp_sync_info;
+
+       ldp_sync_info = circuit->ldp_sync_info;
+
+       /* received sync-complete from LDP:
+        *  set state to up
+        *  stop timer
+        *  restore interface cost to original value
+        */
+       if (ldp_sync_info && ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED) {
+               if (ldp_sync_info->state == LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP)
+                       ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_UP;
+               THREAD_TIMER_OFF(ldp_sync_info->t_holddown);
+               ldp_sync_info->t_holddown = NULL;
+               isis_ldp_sync_set_if_metric(circuit, true);
+       }
+}
+
+void isis_ldp_sync_ldp_fail(struct isis_circuit *circuit)
+{
+       struct ldp_sync_info *ldp_sync_info;
+
+       ldp_sync_info = circuit->ldp_sync_info;
+
+       /* LDP failed to send hello:
+        *  stop holddown timer
+        *  set cost of interface to LSInfinity so traffic will use different
+        *  interface until LDP restarts and has learned all labels from peer
+        */
+       if (ldp_sync_info &&
+           ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED &&
+           ldp_sync_info->state != LDP_IGP_SYNC_STATE_NOT_REQUIRED) {
+               if (ldp_sync_info->t_holddown != NULL) {
+                       THREAD_TIMER_OFF(ldp_sync_info->t_holddown);
+                       ldp_sync_info->t_holddown = NULL;
+               }
+               ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
+               isis_ldp_sync_set_if_metric(circuit, true);
+       }
+}
+
+void isis_ldp_sync_if_remove(struct isis_circuit *circuit, bool remove)
+{
+       struct ldp_sync_info *ldp_sync_info;
+
+       if (circuit->ldp_sync_info == NULL)
+               return;
+
+       ldp_sync_info = circuit->ldp_sync_info;
+
+       /* Stop LDP-SYNC on this interface:
+        *  if holddown timer is running stop it
+        *  delete ldp instance on interface
+        *  restore metric
+        */
+       ils_debug("ldp_sync: remove if %s", circuit->interface
+                 ? circuit->interface->name : "");
+
+       if (ldp_sync_info->t_holddown)
+               THREAD_TIMER_OFF(ldp_sync_info->t_holddown);
+       ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED;
+       isis_ldp_sync_set_if_metric(circuit, true);
+       if (remove) {
+               /* ISIS instance being removed free ldp-sync info */
+               ldp_sync_info_free((struct ldp_sync_info **)&(ldp_sync_info));
+               circuit->ldp_sync_info = NULL;
+       }
+}
+
+static int isis_ldp_sync_adj_state_change(struct isis_adjacency *adj)
+{
+       struct isis_circuit *circuit = adj->circuit;
+       struct ldp_sync_info *ldp_sync_info;
+       struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+       if (!isis ||
+           !CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE) ||
+           circuit->interface->vrf_id != VRF_DEFAULT ||
+           if_is_loopback(circuit->interface))
+               return 0;
+
+       if (circuit->ldp_sync_info == NULL)
+               isis_ldp_sync_if_init(circuit, isis);
+       ldp_sync_info = circuit->ldp_sync_info;
+
+       if (ldp_sync_info->enabled != LDP_IGP_SYNC_ENABLED)
+               return 0;
+
+       if (adj->adj_state == ISIS_ADJ_UP) {
+               if (circuit->circ_type == CIRCUIT_T_P2P ||
+                   if_is_pointopoint(circuit->interface)) {
+                       /* If LDP-SYNC is configure on interface then start */
+                       ldp_sync_info->state =
+                               LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
+                       isis_ldp_sync_if_start(circuit, true);
+               } else {
+                       /* non ptop link so don't run ldp-sync */
+                       ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED;
+                       isis_ldp_sync_set_if_metric(circuit, true);
+               }
+       } else {
+               /* If LDP-SYNC is configure on this interface then stop it */
+               if (circuit->circ_type == CIRCUIT_T_P2P ||
+                   if_is_pointopoint(circuit->interface))
+                       ldp_sync_info->state =
+                               LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
+               else
+                       ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED;
+
+               ils_debug("ldp_sync: down on if %s", circuit->interface->name);
+               ldp_sync_if_down(circuit->ldp_sync_info);
+       }
+
+       return 0;
+}
+
+bool isis_ldp_sync_if_metric_config(struct isis_circuit *circuit, int level,
+                                   int metric)
+{
+       struct ldp_sync_info *ldp_sync_info = circuit->ldp_sync_info;
+       struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+       /* configured interface metric has been changed:
+        *   if LDP-IGP Sync is running and metric has been set to LSInfinity
+        *   change saved value so when ldp-sync completes proper metric is
+        *   restored
+        */
+       if (isis &&
+           CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE) &&
+           ldp_sync_info != NULL) {
+
+               if (CHECK_FLAG(ldp_sync_info->flags,
+                              LDP_SYNC_FLAG_SET_METRIC)) {
+                       ldp_sync_info->metric[level-1] = metric;
+                       ldp_sync_info->metric[level-1] = metric;
+                       return false;
+               }
+       }
+       return true;
+}
+
+void isis_ldp_sync_set_if_metric(struct isis_circuit *circuit, bool run_regen)
+{
+       struct ldp_sync_info *ldp_sync_info;
+
+       /* set interface metric:
+        *   if LDP-IGP Sync is starting set metric so interface
+        *   is used only as last resort
+        *   else restore metric to original value
+        */
+       if (circuit->ldp_sync_info == NULL || circuit->area == NULL)
+               return;
+
+       ldp_sync_info = circuit->ldp_sync_info;
+       if (ldp_sync_if_is_enabled(ldp_sync_info)) {
+               /* if metric already set to LSInfinity just return */
+               if (CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_SET_METRIC))
+                       return;
+
+               SET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_SET_METRIC);
+               if (circuit->is_type & IS_LEVEL_1) {
+                       if (circuit->area->newmetric) {
+                               ldp_sync_info->metric[0] =
+                                       circuit->te_metric[0];
+                               circuit->te_metric[0] = LDP_ISIS_LSINFINITY;
+                       } else {
+                               ldp_sync_info->metric[0] = circuit->metric[0];
+                               circuit->metric[0] = LDP_ISIS_LSINFINITY_NL;
+                       }
+               }
+               if (circuit->is_type & IS_LEVEL_2) {
+                       if (circuit->area->newmetric) {
+                               ldp_sync_info->metric[1] =
+                                       circuit->te_metric[1];
+                               circuit->te_metric[1] = LDP_ISIS_LSINFINITY;
+                       } else {
+                               ldp_sync_info->metric[1] = circuit->metric[1];
+                               circuit->metric[1] = LDP_ISIS_LSINFINITY_NL;
+                       }
+               }
+       } else {
+               /* if metric already restored just return */
+               if (!CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_SET_METRIC))
+                       return;
+
+               UNSET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_SET_METRIC);
+               if (circuit->is_type & IS_LEVEL_1) {
+                       circuit->te_metric[0] = ldp_sync_info->metric[0];
+                       circuit->metric[0] = ldp_sync_info->metric[0];
+               }
+               if (circuit->is_type & IS_LEVEL_2) {
+                       circuit->te_metric[1] = ldp_sync_info->metric[1];
+                       circuit->metric[1] = ldp_sync_info->metric[1];
+               }
+       }
+
+       if (run_regen)
+               lsp_regenerate_schedule(circuit->area, circuit->is_type, 0);
+}
+
+
+/*
+ * LDP-SYNC holddown timer routines
+ */
+static int isis_ldp_sync_holddown_timer(struct thread *thread)
+{
+       struct isis_circuit *circuit;
+       struct ldp_sync_info *ldp_sync_info;
+
+       /* holddown timer expired:
+        *  didn't receive msg from LDP indicating sync-complete
+        *  restore interface cost to original value
+        */
+       circuit = THREAD_ARG(thread);
+       if (circuit->ldp_sync_info == NULL)
+               return 0;
+
+       ldp_sync_info = circuit->ldp_sync_info;
+
+       ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_UP;
+       ldp_sync_info->t_holddown = NULL;
+
+       ils_debug("ldp_sync: holddown timer expired for %s state:sync achieved",
+                 circuit->interface->name);
+
+       isis_ldp_sync_set_if_metric(circuit, true);
+       return 0;
+}
+
+void isis_ldp_sync_holddown_timer_add(struct isis_circuit *circuit)
+{
+       struct ldp_sync_info *ldp_sync_info;
+
+       ldp_sync_info = circuit->ldp_sync_info;
+
+       /* Start holddown timer:
+        *  this timer is used to keep interface cost at LSInfinity
+        *  once expires returns cost to original value
+        *  if timer is already running or holddown time is off just return
+        */
+       if (ldp_sync_info->t_holddown ||
+           ldp_sync_info->holddown == LDP_IGP_SYNC_HOLDDOWN_DEFAULT)
+               return;
+
+       ils_debug("ldp_sync: start holddown timer for %s time %d",
+                 circuit->interface->name, ldp_sync_info->holddown);
+
+       thread_add_timer(master, isis_ldp_sync_holddown_timer,
+                        circuit, ldp_sync_info->holddown,
+                        &ldp_sync_info->t_holddown);
+}
+
+/*
+ * LDP-SYNC hello timer routines
+ */
+static int isis_ldp_sync_hello_timer(struct thread *thread)
+{
+       struct isis_area *area;
+       struct listnode *node;
+       struct isis_circuit *circuit;
+       struct interface *ifp;
+       struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+       struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+       if (!isis)
+               return 0;
+
+       /* hello timer expired:
+        *  didn't receive hello msg from LDP
+        *  set cost of all interfaces to LSInfinity
+        */
+       FOR_ALL_INTERFACES (vrf, ifp) {
+               for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
+                       circuit = circuit_lookup_by_ifp(ifp,
+                                                       area->circuit_list);
+                       if (circuit == NULL)
+                               continue;
+
+                       isis_ldp_sync_ldp_fail(circuit);
+               }
+       }
+
+       zlog_debug("ldp_sync: hello timer expired, LDP down");
+
+       return 0;
+}
+
+void isis_ldp_sync_hello_timer_add(void)
+{
+       struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+       /* Start hello timer:
+        *  this timer is used to make sure LDP is up
+        *  if expires set interface cost to LSInfinity
+        */
+       if (!isis ||
+           !CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
+               return;
+
+       thread_add_timer(master, isis_ldp_sync_hello_timer,
+                        NULL, LDP_IGP_SYNC_HELLO_TIMEOUT,
+                        &isis->ldp_sync_cmd.t_hello);
+}
+
+/*
+ * LDP-SYNC routes used by set commands.
+ */
+
+void isis_if_set_ldp_sync_enable(struct isis_circuit *circuit)
+{
+       struct ldp_sync_info *ldp_sync_info;
+       struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+       /* called when setting LDP-SYNC at the global level:
+        *  specifed on interface overrides global config
+        *  if ptop link send msg to LDP indicating ldp-sync enabled
+        */
+       if (!isis || if_is_loopback(circuit->interface))
+               return;
+
+       if (CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) {
+               if (circuit->ldp_sync_info == NULL)
+                       isis_ldp_sync_if_init(circuit, isis);
+               ldp_sync_info = circuit->ldp_sync_info;
+
+               /* config on interface, overrides global config. */
+               if (CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG))
+                       if (ldp_sync_info->enabled != LDP_IGP_SYNC_ENABLED)
+                           return;
+
+               ldp_sync_info->enabled = LDP_IGP_SYNC_ENABLED;
+               ils_debug("ldp_sync: enable if %s", circuit->interface->name);
+
+               /* send message to LDP if ptop link */
+               if (circuit->circ_type == CIRCUIT_T_P2P ||
+                   if_is_pointopoint(circuit->interface)) {
+                       ldp_sync_info->state =
+                               LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
+                       isis_ldp_sync_state_req_msg(circuit);
+               } else {
+                       ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED;
+                       zlog_debug("ldp_sync: Sync only runs on P2P links %s",
+                                  circuit->interface->name);
+               }
+       } else
+               /* delete LDP sync even if configured on an interface */
+               isis_ldp_sync_if_remove(circuit, false);
+}
+
+void isis_if_set_ldp_sync_holddown(struct isis_circuit *circuit)
+{
+       struct ldp_sync_info *ldp_sync_info;
+       struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+       /* called when setting LDP-SYNC at the global level:
+        *  specifed on interface overrides global config.
+        */
+       if (!isis || if_is_loopback(circuit->interface))
+               return;
+
+       if (circuit->ldp_sync_info == NULL)
+               isis_ldp_sync_if_init(circuit, isis);
+       ldp_sync_info = circuit->ldp_sync_info;
+
+       /* config on interface, overrides global config. */
+       if (CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN))
+               return;
+       if (CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN))
+               ldp_sync_info->holddown = isis->ldp_sync_cmd.holddown;
+       else
+               ldp_sync_info->holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT;
+}
+
+void isis_ldp_sync_gbl_exit(bool remove)
+{
+       struct isis_area *area;
+       struct listnode *node;
+       struct isis_circuit *circuit;
+       struct interface *ifp;
+       struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+       struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+       /* if you delete LDP-SYNC at a gobal level is clears all LDP-SYNC
+        * configuration, even interface configuration
+        */
+       if (isis &&
+           CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) {
+               /* register with opaque client to recv LDP-IGP Sync msgs */
+               zclient_unregister_opaque(zclient,
+                                         LDP_IGP_SYNC_IF_STATE_UPDATE);
+               zclient_unregister_opaque(zclient,
+                                         LDP_IGP_SYNC_ANNOUNCE_UPDATE);
+               zclient_unregister_opaque(zclient, LDP_IGP_SYNC_HELLO_UPDATE);
+
+               /* disable LDP-SYNC globally */
+               UNSET_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE);
+               UNSET_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN);
+               isis->ldp_sync_cmd.holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT;
+               THREAD_TIMER_OFF(isis->ldp_sync_cmd.t_hello);
+               isis->ldp_sync_cmd.t_hello = NULL;
+
+               /* remove LDP-SYNC on all ISIS interfaces */
+               FOR_ALL_INTERFACES (vrf, ifp) {
+                       for (ALL_LIST_ELEMENTS_RO(isis->area_list, node,
+                                                 area)) {
+                               circuit = circuit_lookup_by_ifp(ifp,
+                                       area->circuit_list);
+                               if (circuit == NULL)
+                                       continue;
+                               isis_ldp_sync_if_remove(circuit, remove);
+                       }
+               }
+       }
+}
+
+/*
+ * LDP-SYNC routines used by show commands.
+ */
+
+static void isis_circuit_ldp_sync_print_vty(struct isis_circuit *circuit,
+       struct vty *vty)
+{
+       struct ldp_sync_info *ldp_sync_info;
+       const char *ldp_state;
+
+       if (circuit->ldp_sync_info == NULL ||
+           if_is_loopback(circuit->interface))
+               return;
+
+       ldp_sync_info = circuit->ldp_sync_info;
+       vty_out(vty, "%-10s\n", circuit->interface->name);
+       vty_out(vty, "  LDP-IGP Synchronization enabled: %s\n",
+               ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED
+               ? "yes"
+               : "no");
+       vty_out(vty, "  holddown timer in seconds: %u\n",
+               ldp_sync_info->holddown);
+
+       switch (ldp_sync_info->state) {
+       case LDP_IGP_SYNC_STATE_REQUIRED_UP:
+               vty_out(vty, "  State: Sync achieved\n");
+               break;
+       case LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP:
+               if (ldp_sync_info->t_holddown != NULL) {
+                       struct timeval remain = thread_timer_remain(
+                               ldp_sync_info->t_holddown);
+                       vty_out(vty,
+                               "  Holddown timer is running %lld.%03lld remaining\n",
+                               (long long)remain.tv_sec,
+                               (long long)remain.tv_usec/1000);
+
+                       vty_out(vty, "  State: Holding down until Sync\n");
+               } else
+                       vty_out(vty, "  State: Sync not achieved\n");
+               break;
+       case LDP_IGP_SYNC_STATE_NOT_REQUIRED:
+       default:
+               if ((circuit->circ_type != CIRCUIT_T_P2P &&
+                    !if_is_pointopoint(circuit->interface)) &&
+                   circuit->circ_type != CIRCUIT_T_UNKNOWN)
+                       ldp_state = "Sync not required: non-p2p link";
+               else
+                       ldp_state = "Sync not required";
+               vty_out(vty, "  State: %s\n", ldp_state);
+               break;
+       }
+}
+
+DEFUN (show_isis_mpls_ldp_interface,
+       show_isis_mpls_ldp_interface_cmd,
+       "show " PROTO_NAME " mpls ldp-sync [interface <INTERFACE|all>]",
+       SHOW_STR
+       PROTO_HELP
+       MPLS_STR
+       "LDP-IGP Sync information\n"
+       "Interface name\n")
+{
+       char *ifname = NULL;
+       int idx_intf = 0;
+       struct listnode *anode, *cnode;
+       struct isis_area *area;
+       struct isis_circuit *circuit;
+       struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+       if (!isis) {
+               vty_out(vty, "IS-IS Routing Process not enabled\n");
+               return CMD_SUCCESS;
+       }
+
+       if (!CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) {
+               vty_out(vty, "LDP-sync is disabled\n");
+               return CMD_SUCCESS;
+       }
+
+       if (argv_find(argv, argc, "INTERFACE", &idx_intf))
+               ifname = argv[idx_intf]->arg;
+
+       for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) {
+               for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit))
+                       if (!ifname)
+                               isis_circuit_ldp_sync_print_vty(circuit, vty);
+                       else if (strcmp(circuit->interface->name, ifname) == 0)
+                               isis_circuit_ldp_sync_print_vty(circuit, vty);
+       }
+
+       return CMD_SUCCESS;
+}
+
+void isis_ldp_sync_init(void)
+{
+
+       /* "show ip isis mpls ldp interface" commands. */
+       install_element(VIEW_NODE, &show_isis_mpls_ldp_interface_cmd);
+
+       /* register for adjacency state changes */
+       hook_register(isis_adj_state_change_hook,
+                     isis_ldp_sync_adj_state_change);
+}
diff --git a/isisd/isis_ldp_sync.h b/isisd/isis_ldp_sync.h
new file mode 100644 (file)
index 0000000..6017cdf
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * isis_ldp_sync.h: ISIS LDP-IGP Sync  handling routines
+ * Copyright (C) 2020 Volta Networks, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _ZEBRA_ISIS_LDP_SYNC_H
+#define _ZEBRA_ISIS_LDP_SYNC_H
+
+#define LDP_ISIS_LSINFINITY 0xFFFFFE  /* wide link metric */
+#define LDP_ISIS_LSINFINITY_NL 62     /* narrow link metric */
+
+/* Macro to log debug message */
+#define ils_debug(...)                                                         \
+       do {                                                                   \
+               if (IS_DEBUG_LDP_SYNC)                                         \
+                       zlog_debug(__VA_ARGS__);                               \
+       } while (0)
+
+extern void isis_if_set_ldp_sync_enable(struct isis_circuit *circuit);
+extern void isis_if_set_ldp_sync_holddown(struct  isis_circuit *circuit);
+extern void isis_ldp_sync_if_init(struct isis_circuit *circuit,
+                                 struct isis *isis);
+extern void isis_ldp_sync_if_start(struct isis_circuit *circuit,
+                                  bool send_state_req);
+extern void isis_ldp_sync_if_remove(struct isis_circuit *circuit, bool remove);
+extern void isis_ldp_sync_if_complete(struct isis_circuit *circuit);
+extern void isis_ldp_sync_holddown_timer_add(struct isis_circuit *circuit);
+extern void isis_ldp_sync_hello_timer_add(void);
+extern void isis_ldp_sync_ldp_fail(struct isis_circuit *circuit);
+extern int isis_ldp_sync_state_update(struct ldp_igp_sync_if_state state);
+extern int isis_ldp_sync_announce_update(struct ldp_igp_sync_announce announce);
+extern int isis_ldp_sync_hello_update(struct ldp_igp_sync_hello hello);
+extern void isis_ldp_sync_state_req_msg(struct isis_circuit *circuit);
+extern void isis_ldp_sync_set_if_metric(struct isis_circuit *circuit,
+                                       bool run_regen);
+extern bool isis_ldp_sync_if_metric_config(struct isis_circuit *circuit,
+                                          int level, int metric);
+extern void isis_ldp_sync_init(void);
+extern void isis_ldp_sync_gbl_exit(bool remove);
+#endif /* _ZEBRA_ISIS_LDP_SYNC_H */
index ed4b206851f57c01119a4fb49ffeee6133f0f262..fb173eae6290d5e00bd1ad902c0dcb6688e00122 100644 (file)
@@ -58,6 +58,7 @@
 #include "isisd/isis_mt.h"
 #include "isisd/fabricd.h"
 #include "isisd/isis_nb.h"
+#include "isisd/isis_ldp_sync.h"
 
 /* Default configuration file name */
 #define ISISD_DEFAULT_CONFIG "isisd.conf"
@@ -265,6 +266,7 @@ int main(int argc, char **argv, char **envp)
 
        isis_zebra_init(master, instance);
        isis_bfd_init();
+       isis_ldp_sync_init();
        fabricd_init();
 
        frr_config_fork();
index 2b8b02e3f1510a8a727aa38424828b5e768c5132..82491acd86d937c8dc0c5b981d7b576171999985 100644 (file)
@@ -537,6 +537,21 @@ const struct frr_yang_module_info frr_isisd_info = {
                                .modify = isis_instance_segment_routing_prefix_sid_map_prefix_sid_last_hop_behavior_modify,
                        },
                },
+               {
+                       .xpath = "/frr-isisd:isis/instance/mpls/ldp-sync",
+                       .cbs = {
+                               .cli_show = cli_show_isis_mpls_ldp_sync,
+                               .create = isis_instance_mpls_ldp_sync_create,
+                               .destroy = isis_instance_mpls_ldp_sync_destroy,
+                       },
+               },
+               {
+                       .xpath = "/frr-isisd:isis/instance/mpls/ldp-sync/holddown",
+                       .cbs = {
+                               .cli_show = cli_show_isis_mpls_ldp_sync_holddown,
+                               .modify = isis_instance_mpls_ldp_sync_holddown_modify,
+                       },
+               },
                {
                        .xpath = "/frr-interface:lib/interface/frr-isisd:isis",
                        .cbs = {
@@ -898,6 +913,21 @@ const struct frr_yang_module_info frr_isisd_info = {
                                .get_elem = lib_interface_state_isis_event_counters_authentication_fails_get_elem,
                        }
                },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-isisd:isis/mpls/ldp-sync",
+                       .cbs = {
+                               .cli_show = cli_show_isis_mpls_if_ldp_sync,
+                               .modify = lib_interface_isis_mpls_ldp_sync_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-isisd:isis/mpls/holddown",
+                       .cbs = {
+                               .cli_show = cli_show_isis_mpls_if_ldp_sync_holddown,
+                               .modify = lib_interface_isis_mpls_holddown_modify,
+                               .destroy = lib_interface_isis_mpls_holddown_destroy,
+                       }
+               },
                {
                        .xpath = NULL,
                },
index a9401bc86aa968bb07e02e5fc323da1670aa8f2b..db470d138176bfe6bd2cbef9614c648fdc825343 100644 (file)
@@ -205,6 +205,9 @@ int isis_instance_segment_routing_prefix_sid_map_prefix_sid_sid_value_modify(
        struct nb_cb_modify_args *args);
 int isis_instance_segment_routing_prefix_sid_map_prefix_sid_last_hop_behavior_modify(
        struct nb_cb_modify_args *args);
+int isis_instance_mpls_ldp_sync_destroy(struct nb_cb_destroy_args *args);
+int isis_instance_mpls_ldp_sync_create(struct nb_cb_create_args *args);
+int isis_instance_mpls_ldp_sync_holddown_modify(struct nb_cb_modify_args *args);
 int lib_interface_isis_csnp_interval_level_1_modify(
        struct nb_cb_modify_args *args);
 int lib_interface_isis_csnp_interval_level_2_modify(
@@ -249,6 +252,9 @@ int lib_interface_isis_multi_topology_ipv6_management_modify(
        struct nb_cb_modify_args *args);
 int lib_interface_isis_multi_topology_ipv6_dstsrc_modify(
        struct nb_cb_modify_args *args);
+int lib_interface_isis_mpls_ldp_sync_modify(struct nb_cb_modify_args *args);
+int lib_interface_isis_mpls_holddown_modify(struct nb_cb_modify_args *args);
+int lib_interface_isis_mpls_holddown_destroy(struct nb_cb_destroy_args *args);
 struct yang_data *
 lib_interface_state_isis_get_elem(struct nb_cb_get_elem_args *args);
 const void *lib_interface_state_isis_adjacencies_adjacency_get_next(
@@ -433,6 +439,16 @@ void cli_show_ip_isis_priority(struct vty *vty, struct lyd_node *dnode,
                               bool show_defaults);
 void cli_show_isis_log_adjacency(struct vty *vty, struct lyd_node *dnode,
                                 bool show_defaults);
+void cli_show_isis_mpls_ldp_sync(struct vty *vty, struct lyd_node *dnode,
+                                bool show_defaults);
+void cli_show_isis_mpls_ldp_sync_holddown(struct vty *vty,
+                                         struct lyd_node *dnode,
+                                         bool show_defaults);
+void cli_show_isis_mpls_if_ldp_sync(struct vty *vty, struct lyd_node *dnode,
+                                   bool show_defaults);
+void cli_show_isis_mpls_if_ldp_sync_holddown(struct vty *vty,
+                                            struct lyd_node *dnode,
+                                            bool show_defaults);
 
 /* Notifications. */
 void isis_notif_db_overload(const struct isis_area *area, bool overload);
index ffc3d5b2e00cb952cab3ff41d46591b16564f73b..a2ddc4057ddc170c353b83a9c696a1ef2e6c654f 100644 (file)
@@ -29,6 +29,8 @@
 #include "spf_backoff.h"
 #include "lib_errors.h"
 #include "vrf.h"
+#include "zclient.h"
+#include "ldp_sync.h"
 
 #include "isisd/isisd.h"
 #include "isisd/isis_nb.h"
@@ -45,6 +47,9 @@
 #include "isisd/isis_memory.h"
 #include "isisd/isis_mt.h"
 #include "isisd/isis_redist.h"
+#include "isisd/isis_ldp_sync.h"
+
+extern struct zclient *zclient;
 
 /*
  * XPath: /frr-isisd:isis/instance
@@ -79,6 +84,10 @@ int isis_instance_destroy(struct nb_cb_destroy_args *args)
        area = nb_running_unset_entry(args->dnode);
        isis_area_destroy(area);
 
+       /* remove ldp-sync config */
+       if (area->isis->vrf_id == VRF_DEFAULT)
+               isis_ldp_sync_gbl_exit(true);
+
        return NB_OK;
 }
 
@@ -1823,6 +1832,113 @@ int isis_instance_segment_routing_prefix_sid_map_prefix_sid_last_hop_behavior_mo
        return NB_OK;
 }
 
+/*
+ * XPath: /frr-isisd:isis/instance/mpls/ldp-sync
+ */
+int isis_instance_mpls_ldp_sync_create(struct nb_cb_create_args *args)
+{
+       struct isis_area *area;
+       struct listnode *node;
+       struct isis_circuit *circuit;
+       struct interface *ifp;
+       struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+       struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+               if (isis == NULL)
+                       return NB_ERR_VALIDATION;
+               break;
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               /* register with opaque client to recv LDP-IGP Sync msgs */
+               zclient_register_opaque(zclient, LDP_IGP_SYNC_IF_STATE_UPDATE);
+               zclient_register_opaque(zclient, LDP_IGP_SYNC_ANNOUNCE_UPDATE);
+               zclient_register_opaque(zclient, LDP_IGP_SYNC_HELLO_UPDATE);
+
+               if (!CHECK_FLAG(isis->ldp_sync_cmd.flags,
+                               LDP_SYNC_FLAG_ENABLE)) {
+                       SET_FLAG(isis->ldp_sync_cmd.flags,
+                                LDP_SYNC_FLAG_ENABLE);
+
+                       /* turn on LDP-IGP Sync on all ptop ISIS interfaces */
+                       FOR_ALL_INTERFACES (vrf, ifp) {
+                               for (ALL_LIST_ELEMENTS_RO(isis->area_list, node,
+                                                         area)) {
+                                       circuit = circuit_lookup_by_ifp(
+                                               ifp, area->circuit_list);
+                                       if (circuit == NULL)
+                                               continue;
+                                       isis_if_set_ldp_sync_enable(circuit);
+                               }
+                       }
+               }
+               break;
+       }
+       return NB_OK;
+}
+
+int isis_instance_mpls_ldp_sync_destroy(struct nb_cb_destroy_args *args)
+{
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       /* remove ldp-sync config */
+       isis_ldp_sync_gbl_exit(false);
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/mpls/ldp-sync/holddown
+ */
+int isis_instance_mpls_ldp_sync_holddown_modify(struct nb_cb_modify_args *args)
+{
+       struct isis_area *area;
+       struct listnode *node;
+       struct isis_circuit *circuit;
+       struct interface *ifp;
+       struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+       uint16_t holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT;
+       struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+               if (isis == NULL)
+                       return NB_ERR_VALIDATION;
+               break;
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               holddown = yang_dnode_get_uint16(args->dnode, NULL);
+
+               if (holddown == LDP_IGP_SYNC_HOLDDOWN_DEFAULT)
+                       UNSET_FLAG(isis->ldp_sync_cmd.flags,
+                                  LDP_SYNC_FLAG_HOLDDOWN);
+               else
+                       SET_FLAG(isis->ldp_sync_cmd.flags,
+                                LDP_SYNC_FLAG_HOLDDOWN);
+               isis->ldp_sync_cmd.holddown = holddown;
+
+               /* set holddown time on all ISIS interfaces */
+               FOR_ALL_INTERFACES (vrf, ifp) {
+                       for (ALL_LIST_ELEMENTS_RO(isis->area_list, node,
+                                                 area)) {
+                               circuit = circuit_lookup_by_ifp(ifp,
+                                                       area->circuit_list);
+                               if (circuit == NULL)
+                                       continue;
+                               isis_if_set_ldp_sync_holddown(circuit);
+                       }
+               }
+               break;
+       }
+       return NB_OK;
+}
+
 /*
  * XPath: /frr-interface:lib/interface/frr-isisd:isis
  */
@@ -1904,6 +2020,9 @@ int lib_interface_isis_destroy(struct nb_cb_destroy_args *args)
        if (!circuit)
                return NB_ERR_INCONSISTENCY;
 
+       /* remove ldp-sync config */
+       isis_ldp_sync_if_remove(circuit, true);
+
        /* disable both AFs for this circuit. this will also update the
         * CSM state by sending an ISIS_DISABLED signal. If there is no
         * area associated to the circuit there is nothing to do
@@ -2597,3 +2716,130 @@ int lib_interface_isis_multi_topology_ipv6_dstsrc_modify(
                args->event, args->dnode, args->errmsg, args->errmsg_len,
                ISIS_MT_IPV6_DSTSRC);
 }
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/mpls/ldp-sync
+ */
+int lib_interface_isis_mpls_ldp_sync_modify(struct nb_cb_modify_args *args)
+{
+       struct isis_circuit *circuit;
+       struct ldp_sync_info *ldp_sync_info;
+       bool ldp_sync_enable;
+       struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+               if (isis == NULL)
+                       return NB_ERR_VALIDATION;
+               break;
+
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               circuit = nb_running_get_entry(args->dnode, NULL, true);
+               ldp_sync_enable = yang_dnode_get_bool(args->dnode, NULL);
+
+               if (circuit->ldp_sync_info == NULL)
+                       isis_ldp_sync_if_init(circuit, isis);
+               ldp_sync_info = circuit->ldp_sync_info;
+
+               if (ldp_sync_enable) {
+                       /* enable LDP-SYNC on an interface
+                        *  if ptop interface send message to LDP to get state
+                        */
+                       SET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG);
+                       ldp_sync_info->enabled = LDP_IGP_SYNC_ENABLED;
+                       if (circuit->circ_type == CIRCUIT_T_P2P) {
+                               ldp_sync_info->state =
+                                       LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
+                               isis_ldp_sync_state_req_msg(circuit);
+                       } else {
+                               zlog_debug("ldp_sync: only runs on P2P links %s",
+                                          circuit->interface->name);
+                               ldp_sync_info->state =
+                                       LDP_IGP_SYNC_STATE_NOT_REQUIRED;
+                       }
+               } else {
+                       /* disable LDP-SYNC on an interface
+                        *  stop holddown timer if running
+                        *  restore isis metric
+                        */
+                       SET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG);
+                       ldp_sync_info->enabled = LDP_IGP_SYNC_DEFAULT;
+                       ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED;
+                       THREAD_TIMER_OFF(ldp_sync_info->t_holddown);
+                       ldp_sync_info->t_holddown = NULL;
+                       isis_ldp_sync_set_if_metric(circuit, true);
+               }
+               break;
+       }
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/mpls/holddown
+ */
+int lib_interface_isis_mpls_holddown_modify(struct nb_cb_modify_args *args)
+{
+       struct isis_circuit *circuit;
+       struct ldp_sync_info *ldp_sync_info;
+       uint16_t holddown;
+       struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+               if (isis == NULL)
+                       return NB_ERR_VALIDATION;
+               break;
+
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               circuit = nb_running_get_entry(args->dnode, NULL, true);
+               holddown = yang_dnode_get_uint16(args->dnode, NULL);
+
+               if (circuit->ldp_sync_info == NULL)
+                       isis_ldp_sync_if_init(circuit, isis);
+               ldp_sync_info = circuit->ldp_sync_info;
+
+               SET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN);
+               ldp_sync_info->holddown = holddown;
+               break;
+       }
+       return NB_OK;
+}
+
+int lib_interface_isis_mpls_holddown_destroy(struct nb_cb_destroy_args *args)
+{
+       struct isis_circuit *circuit;
+       struct ldp_sync_info *ldp_sync_info;
+       struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+               if (isis == NULL)
+                       return NB_ERR_VALIDATION;
+               circuit = nb_running_get_entry(args->dnode, NULL, true);
+               if (circuit->ldp_sync_info == NULL)
+                       return NB_ERR_VALIDATION;
+
+               break;
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               circuit = nb_running_get_entry(args->dnode, NULL, true);
+               ldp_sync_info = circuit->ldp_sync_info;
+               UNSET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN);
+
+               if (CHECK_FLAG(isis->ldp_sync_cmd.flags,
+                              LDP_SYNC_FLAG_HOLDDOWN))
+                       ldp_sync_info->holddown = isis->ldp_sync_cmd.holddown;
+               else
+                       ldp_sync_info->holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT;
+               break;
+       }
+       return NB_OK;
+}
index 3aa21a9aed259753ca73b034d8fa4b496804a993..e31372d641fcb2e16a02e30500de3c5e8eb57993 100644 (file)
@@ -52,6 +52,7 @@
 #include "isisd/isis_adjacency.h"
 #include "isisd/isis_te.h"
 #include "isisd/isis_sr.h"
+#include "isisd/isis_ldp_sync.h"
 
 struct zclient *zclient;
 static struct zclient *zclient_sync;
@@ -582,6 +583,44 @@ static void isis_zebra_connected(struct zclient *zclient)
        zclient_send_reg_requests(zclient, VRF_DEFAULT);
 }
 
+/*
+ * opaque messages between processes
+ */
+static int isis_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
+{
+       struct stream *s;
+       struct zapi_opaque_msg info;
+       struct ldp_igp_sync_if_state state;
+       struct ldp_igp_sync_announce announce;
+       struct ldp_igp_sync_hello hello;
+       int ret = 0;
+
+       s = zclient->ibuf;
+       if (zclient_opaque_decode(s, &info) != 0)
+               return -1;
+
+       switch (info.type) {
+       case LDP_IGP_SYNC_IF_STATE_UPDATE:
+               STREAM_GET(&state, s, sizeof(state));
+               ret = isis_ldp_sync_state_update(state);
+               break;
+       case LDP_IGP_SYNC_ANNOUNCE_UPDATE:
+               STREAM_GET(&announce, s, sizeof(announce));
+               ret = isis_ldp_sync_announce_update(announce);
+               break;
+       case LDP_IGP_SYNC_HELLO_UPDATE:
+               STREAM_GET(&hello, s, sizeof(hello));
+               ret = isis_ldp_sync_hello_update(hello);
+               break;
+       default:
+               break;
+       }
+
+stream_failure:
+
+       return ret;
+}
+
 void isis_zebra_init(struct thread_master *master, int instance)
 {
        /* Initialize asynchronous zclient. */
@@ -608,6 +647,8 @@ void isis_zebra_init(struct thread_master *master, int instance)
         */
        zclient_sync->session_id = 1;
        zclient_sync->privs = &isisd_privs;
+
+       zclient->opaque_msg_handler = isis_opaque_msg_handler;
 }
 
 void isis_zebra_stop(void)
index 0d39aba20b421138a9c0fad13e6e539753ed19f5..438d87d9fb5bf00a7a78bddf6497b61dfecf3c92 100644 (file)
@@ -75,6 +75,7 @@ unsigned long debug_flooding;
 unsigned long debug_bfd;
 unsigned long debug_tx_queue;
 unsigned long debug_sr;
+unsigned long debug_ldp_sync;
 
 DEFINE_QOBJ_TYPE(isis_area)
 
@@ -1087,6 +1088,8 @@ void print_debug(struct vty *vty, int flags, int onoff)
                vty_out(vty, "IS-IS Flooding debugging is %s\n", onoffs);
        if (flags & DEBUG_BFD)
                vty_out(vty, "IS-IS BFD debugging is %s\n", onoffs);
+       if (flags & DEBUG_LDP_SYNC)
+               vty_out(vty, "IS-IS ldp-sync debugging is %s\n", onoffs);
 }
 
 DEFUN_NOSH (show_debugging,
@@ -1124,6 +1127,8 @@ DEFUN_NOSH (show_debugging,
                print_debug(vty, DEBUG_FLOODING, 1);
        if (IS_DEBUG_BFD)
                print_debug(vty, DEBUG_BFD, 1);
+       if (IS_DEBUG_LDP_SYNC)
+               print_debug(vty, DEBUG_LDP_SYNC, 1);
        return CMD_SUCCESS;
 }
 
@@ -1192,6 +1197,10 @@ static int config_write_debug(struct vty *vty)
                vty_out(vty, "debug " PROTO_NAME " bfd\n");
                write++;
        }
+       if (IS_DEBUG_LDP_SYNC) {
+               vty_out(vty, "debug " PROTO_NAME " ldp-sync\n");
+               write++;
+       }
        write += spf_backoff_write_config(vty);
 
        return write;
@@ -1548,11 +1557,32 @@ DEFUN (no_debug_isis_bfd,
        return CMD_SUCCESS;
 }
 
-DEFUN(show_hostname, show_hostname_cmd,
-      "show " PROTO_NAME " [vrf <NAME|all>] hostname",
-      SHOW_STR PROTO_HELP VRF_CMD_HELP_STR
-      "All VRFs\n"
-      "IS-IS Dynamic hostname mapping\n")
+DEFUN(debug_isis_ldp_sync, debug_isis_ldp_sync_cmd,
+      "debug " PROTO_NAME " ldp-sync",
+      DEBUG_STR PROTO_HELP PROTO_NAME " interaction with LDP-Sync\n")
+{
+       debug_ldp_sync |= DEBUG_LDP_SYNC;
+       print_debug(vty, DEBUG_LDP_SYNC, 1);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN(no_debug_isis_ldp_sync, no_debug_isis_ldp_sync_cmd,
+      "no debug " PROTO_NAME " ldp-sync",
+      NO_STR UNDEBUG_STR PROTO_HELP PROTO_NAME " interaction with LDP-Sync\n")
+{
+       debug_ldp_sync &= ~DEBUG_LDP_SYNC;
+       print_debug(vty, DEBUG_LDP_SYNC, 0);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (show_hostname,
+       show_hostname_cmd,
+       "show " PROTO_NAME " hostname",
+       SHOW_STR
+       PROTO_HELP
+       "IS-IS Dynamic hostname mapping\n")
 {
        struct listnode *nnode, *inode;
        const char *vrf_name = VRF_DEFAULT_NAME;
@@ -2710,6 +2740,8 @@ void isis_init(void)
        install_element(ENABLE_NODE, &no_debug_isis_lsp_sched_cmd);
        install_element(ENABLE_NODE, &debug_isis_bfd_cmd);
        install_element(ENABLE_NODE, &no_debug_isis_bfd_cmd);
+       install_element(ENABLE_NODE, &debug_isis_ldp_sync_cmd);
+       install_element(ENABLE_NODE, &no_debug_isis_ldp_sync_cmd);
 
        install_element(CONFIG_NODE, &debug_isis_adj_cmd);
        install_element(CONFIG_NODE, &no_debug_isis_adj_cmd);
@@ -2737,6 +2769,8 @@ void isis_init(void)
        install_element(CONFIG_NODE, &no_debug_isis_lsp_sched_cmd);
        install_element(CONFIG_NODE, &debug_isis_bfd_cmd);
        install_element(CONFIG_NODE, &no_debug_isis_bfd_cmd);
+       install_element(CONFIG_NODE, &debug_isis_ldp_sync_cmd);
+       install_element(CONFIG_NODE, &no_debug_isis_ldp_sync_cmd);
 
        install_default(ROUTER_NODE);
 
index 41b69df2bf3cf069fddb04ae67a2b6d94aa27e53..02b5990f1ef15e930f8b6ecafc4864fcac418ac8 100644 (file)
@@ -35,6 +35,7 @@
 #include "isis_lsp.h"
 #include "isis_memory.h"
 #include "qobj.h"
+#include "ldp_sync.h"
 
 #ifdef FABRICD
 static const bool fabricd = true;
@@ -93,6 +94,7 @@ struct isis {
        uint32_t circuit_ids_used[8];     /* 256 bits to track circuit ids 1 through 255 */
 
        struct route_table *ext_info[REDIST_PROTOCOL_COUNT];
+       struct ldp_sync_info_cmd ldp_sync_cmd;  /* MPLS LDP-IGP Sync */
 };
 
 extern struct isis_master *im;
@@ -268,6 +270,7 @@ extern unsigned long debug_flooding;
 extern unsigned long debug_bfd;
 extern unsigned long debug_tx_queue;
 extern unsigned long debug_sr;
+extern unsigned long debug_ldp_sync;
 
 #define DEBUG_ADJ_PACKETS                (1<<0)
 #define DEBUG_SNP_PACKETS                (1<<1)
@@ -282,6 +285,7 @@ extern unsigned long debug_sr;
 #define DEBUG_BFD                        (1<<10)
 #define DEBUG_TX_QUEUE                   (1<<11)
 #define DEBUG_SR                         (1<<12)
+#define DEBUG_LDP_SYNC (1 << 13)
 
 /* Debug related macro. */
 #define IS_DEBUG_ADJ_PACKETS (debug_adj_pkt & DEBUG_ADJ_PACKETS)
@@ -297,6 +301,7 @@ extern unsigned long debug_sr;
 #define IS_DEBUG_BFD (debug_bfd & DEBUG_BFD)
 #define IS_DEBUG_TX_QUEUE (debug_tx_queue & DEBUG_TX_QUEUE)
 #define IS_DEBUG_SR (debug_sr & DEBUG_SR)
+#define IS_DEBUG_LDP_SYNC (debug_ldp_sync & DEBUG_LDP_SYNC)
 
 #define lsp_debug(...)                                                         \
        do {                                                                   \
index 9e855ad8cf2629e6719176d7fc1e20a0be25922a..50d474653465a0e05821e256637c560840f6d5f3 100644 (file)
@@ -8,6 +8,7 @@ sbin_PROGRAMS += isisd/isisd
 dist_examples_DATA += isisd/isisd.conf.sample
 vtysh_scan += \
        isisd/isis_cli.c \
+       isisd/isis_ldp_sync.c \
        isisd/isis_redist.c \
        isisd/isis_spf.c \
        isisd/isis_te.c \
@@ -36,6 +37,7 @@ noinst_HEADERS += \
        isisd/isis_errors.h \
        isisd/isis_events.h \
        isisd/isis_flags.h \
+       isisd/isis_ldp_sync.h \
        isisd/isis_lsp.h \
        isisd/isis_memory.h \
        isisd/isis_misc.h \
@@ -69,6 +71,7 @@ LIBISIS_SOURCES = \
        isisd/isis_errors.c \
        isisd/isis_events.c \
        isisd/isis_flags.c \
+       isisd/isis_ldp_sync.c \
        isisd/isis_lsp.c \
        isisd/isis_memory.c \
        isisd/isis_misc.c \
index 1bb693a1efbc3a5b229ea1148aa00889d90e15bc..c0f128f3d6cee5477cb2224da0757083f8bd229b 100644 (file)
@@ -605,6 +605,26 @@ module frr-isisd {
           "IPv6 destination-source topology.";
       }
     }
+
+    container mpls {
+      description
+        "Configuration of MPLS parameters";
+      leaf ldp-sync {
+        type boolean;
+        default "true";
+        description
+          "Enable MPLS LDP-Sync functionality on this circuit.";
+      }
+      leaf holddown {
+        type uint16 {
+          range "0..10000";
+      }
+      units "seconds";
+      description
+        "Time to wait for LDP-Sync to occur before restoring interface metric.";
+      }
+    }
+
   }
 
   grouping adjacency-state {
@@ -1311,6 +1331,26 @@ module frr-isisd {
           }
         }
       }
+
+      container mpls {
+        description
+          "Configuration of MPLS parameters";
+        container ldp-sync {
+          presence "Present if MPLS LDP-Sync is enabled.";
+          description
+            "Enable MPLS LDP-Sync functionality.";
+          leaf holddown {
+            type uint16 {
+              range "0..10000";
+            }
+            units "seconds";
+            default "0";
+            description
+              "Time to wait for LDP-Sync to occur before restoring interface metric.";
+          }
+        }
+      }
+
     }
   }