]> git.puffer.fish Git - matthieu/frr.git/commitdiff
ospfd: ldp-igp-sync feature: adding ospf support
authorlynne <lynne@voltanet.io>
Wed, 22 Jul 2020 17:31:14 +0000 (13:31 -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>
12 files changed:
ospfd/ospf_dump.c
ospfd/ospf_dump.h
ospfd/ospf_interface.c
ospfd/ospf_interface.h
ospfd/ospf_ldp_sync.c [new file with mode: 0644]
ospfd/ospf_ldp_sync.h [new file with mode: 0644]
ospfd/ospf_main.c
ospfd/ospf_vty.c
ospfd/ospf_zebra.c
ospfd/ospfd.c
ospfd/ospfd.h
ospfd/subdir.am

index dcc479def6b0969418c6dd09a1cbd568f7f15840..e8798e023e2c50324db25f5b8236db717c10a0d2 100644 (file)
@@ -54,6 +54,7 @@ unsigned long conf_debug_ospf_te = 0;
 unsigned long conf_debug_ospf_ext = 0;
 unsigned long conf_debug_ospf_sr = 0;
 unsigned long conf_debug_ospf_defaultinfo = 0;
+unsigned long conf_debug_ospf_ldp_sync = 0;
 
 /* Enable debug option variables -- valid only session. */
 unsigned long term_debug_ospf_packet[5] = {0, 0, 0, 0, 0};
@@ -67,6 +68,7 @@ unsigned long term_debug_ospf_te = 0;
 unsigned long term_debug_ospf_ext = 0;
 unsigned long term_debug_ospf_sr = 0;
 unsigned long term_debug_ospf_defaultinfo;
+unsigned long term_debug_ospf_ldp_sync;
 
 const char *ospf_redist_string(unsigned int route_type)
 {
@@ -1476,6 +1478,32 @@ DEFUN (no_debug_ospf_default_info,
        return CMD_SUCCESS;
 }
 
+DEFUN(debug_ospf_ldp_sync,
+      debug_ospf_ldp_sync_cmd,
+      "debug ospf ldp-sync",
+      DEBUG_STR OSPF_STR
+      "OSPF LDP-Sync information\n")
+{
+       if (vty->node == CONFIG_NODE)
+               CONF_DEBUG_ON(ldp_sync, LDP_SYNC);
+       TERM_DEBUG_ON(ldp_sync, LDP_SYNC);
+       return CMD_SUCCESS;
+}
+
+DEFUN(no_debug_ospf_ldp_sync,
+      no_debug_ospf_ldp_sync_cmd,
+      "no debug ospf ldp-sync",
+      NO_STR
+      DEBUG_STR
+      OSPF_STR
+      "OSPF LDP-Sync information\n")
+{
+       if (vty->node == CONFIG_NODE)
+               CONF_DEBUG_OFF(ldp_sync, LDP_SYNC);
+       TERM_DEBUG_OFF(ldp_sync, LDP_SYNC);
+       return CMD_SUCCESS;
+}
+
 DEFUN (no_debug_ospf,
        no_debug_ospf_cmd,
        "no debug ospf",
@@ -1505,6 +1533,7 @@ DEFUN (no_debug_ospf,
                DEBUG_OFF(zebra, ZEBRA_INTERFACE);
                DEBUG_OFF(zebra, ZEBRA_REDISTRIBUTE);
                DEBUG_OFF(defaultinfo, DEFAULTINFO);
+               DEBUG_OFF(ldp_sync, LDP_SYNC);
 
                for (i = 0; i < 5; i++)
                        DEBUG_PACKET_OFF(i, flag);
@@ -1532,6 +1561,7 @@ DEFUN (no_debug_ospf,
        TERM_DEBUG_OFF(zebra, ZEBRA_INTERFACE);
        TERM_DEBUG_OFF(zebra, ZEBRA_REDISTRIBUTE);
        TERM_DEBUG_OFF(defaultinfo, DEFAULTINFO);
+       TERM_DEBUG_OFF(ldp_sync, LDP_SYNC);
 
        return CMD_SUCCESS;
 }
@@ -1633,6 +1663,10 @@ static int show_debugging_ospf_common(struct vty *vty, struct ospf *ospf)
        if (IS_DEBUG_OSPF(nssa, NSSA) == OSPF_DEBUG_NSSA)
                vty_out(vty, "  OSPF NSSA debugging is on\n");
 
+       /* Show debug status for LDP-SYNC. */
+       if (IS_DEBUG_OSPF(ldp_sync, LDP_SYNC) == OSPF_DEBUG_LDP_SYNC)
+               vty_out(vty, "  OSPF ldp-sync debugging is on\n");
+
        vty_out(vty, "\n");
 
        return CMD_SUCCESS;
@@ -1814,6 +1848,11 @@ static int config_write_debug(struct vty *vty)
                write = 1;
        }
 
+       /* debug ospf ldp-sync */
+       if (IS_CONF_DEBUG_OSPF(ldp_sync, LDP_SYNC) == OSPF_DEBUG_LDP_SYNC) {
+               vty_out(vty, "debug ospf%s ldp-sync\n", str);
+               write = 1;
+       }
        return write;
 }
 
@@ -1832,6 +1871,7 @@ void ospf_debug_init(void)
        install_element(ENABLE_NODE, &debug_ospf_te_cmd);
        install_element(ENABLE_NODE, &debug_ospf_sr_cmd);
        install_element(ENABLE_NODE, &debug_ospf_default_info_cmd);
+       install_element(ENABLE_NODE, &debug_ospf_ldp_sync_cmd);
        install_element(ENABLE_NODE, &no_debug_ospf_ism_cmd);
        install_element(ENABLE_NODE, &no_debug_ospf_nsm_cmd);
        install_element(ENABLE_NODE, &no_debug_ospf_lsa_cmd);
@@ -1841,6 +1881,7 @@ void ospf_debug_init(void)
        install_element(ENABLE_NODE, &no_debug_ospf_te_cmd);
        install_element(ENABLE_NODE, &no_debug_ospf_sr_cmd);
        install_element(ENABLE_NODE, &no_debug_ospf_default_info_cmd);
+       install_element(ENABLE_NODE, &no_debug_ospf_ldp_sync_cmd);
 
        install_element(ENABLE_NODE, &show_debugging_ospf_instance_cmd);
        install_element(ENABLE_NODE, &debug_ospf_packet_cmd);
@@ -1871,6 +1912,7 @@ void ospf_debug_init(void)
        install_element(CONFIG_NODE, &debug_ospf_te_cmd);
        install_element(CONFIG_NODE, &debug_ospf_sr_cmd);
        install_element(CONFIG_NODE, &debug_ospf_default_info_cmd);
+       install_element(CONFIG_NODE, &debug_ospf_ldp_sync_cmd);
        install_element(CONFIG_NODE, &no_debug_ospf_nsm_cmd);
        install_element(CONFIG_NODE, &no_debug_ospf_lsa_cmd);
        install_element(CONFIG_NODE, &no_debug_ospf_zebra_cmd);
@@ -1879,6 +1921,7 @@ void ospf_debug_init(void)
        install_element(CONFIG_NODE, &no_debug_ospf_te_cmd);
        install_element(CONFIG_NODE, &no_debug_ospf_sr_cmd);
        install_element(CONFIG_NODE, &no_debug_ospf_default_info_cmd);
+       install_element(CONFIG_NODE, &no_debug_ospf_ldp_sync_cmd);
 
        install_element(CONFIG_NODE, &debug_ospf_instance_nsm_cmd);
        install_element(CONFIG_NODE, &debug_ospf_instance_lsa_cmd);
index 8c01977ff883b7cd59b22099d808e7d752a02ef0..faae27e2cf593f2c4ff0054d792cc1c8a96e2f23 100644 (file)
@@ -60,6 +60,7 @@
 #define OSPF_DEBUG_EXT         0x08
 #define OSPF_DEBUG_SR          0x10
 #define OSPF_DEBUG_DEFAULTINFO 0x20
+#define OSPF_DEBUG_LDP_SYNC 0x40
 
 /* Macro for setting debug option. */
 #define CONF_DEBUG_PACKET_ON(a, b)         conf_debug_ospf_packet[a] |= (b)
 
 #define IS_DEBUG_OSPF_DEFAULT_INFO IS_DEBUG_OSPF(defaultinfo, DEFAULTINFO)
 
+#define IS_DEBUG_OSPF_LDP_SYNC IS_DEBUG_OSPF(ldp_sync, LDP_SYNC)
+
 #define IS_CONF_DEBUG_OSPF_PACKET(a, b)                                        \
        (conf_debug_ospf_packet[a] & OSPF_DEBUG_##b)
 #define IS_CONF_DEBUG_OSPF(a, b) (conf_debug_ospf_##a & OSPF_DEBUG_##b)
@@ -126,6 +129,7 @@ extern unsigned long term_debug_ospf_te;
 extern unsigned long term_debug_ospf_ext;
 extern unsigned long term_debug_ospf_sr;
 extern unsigned long term_debug_ospf_defaultinfo;
+extern unsigned long term_debug_ospf_ldp_sync;
 
 /* Message Strings. */
 extern char *ospf_lsa_type_str[];
index 7977a2a9f4dedc1eb7c9c05105428e06a49d56c4..d9845f6eb99148a81b077d61a1afb2fa209777bc 100644 (file)
@@ -32,6 +32,7 @@
 #include "log.h"
 #include "zclient.h"
 #include "bfd.h"
+#include "ldp_sync.h"
 
 #include "ospfd/ospfd.h"
 #include "ospfd/ospf_spf.h"
@@ -46,6 +47,7 @@
 #include "ospfd/ospf_abr.h"
 #include "ospfd/ospf_network.h"
 #include "ospfd/ospf_dump.h"
+#include "ospfd/ospf_ldp_sync.h"
 
 DEFINE_QOBJ_TYPE(ospf_interface)
 DEFINE_HOOK(ospf_vl_add, (struct ospf_vl_data * vd), (vd))
@@ -81,6 +83,12 @@ int ospf_if_get_output_cost(struct ospf_interface *oi)
        uint32_t cost;
        uint32_t bw, refbw;
 
+       /* if LDP-IGP Sync is running on interface set cost so interface
+        * is used only as last resort
+        */
+       if (ldp_sync_if_is_enabled(IF_DEF_PARAMS(oi->ifp)->ldp_sync_info))
+               return (LDP_OSPF_LSINFINITY);
+
        /* ifp speed and bw can be 0 in some platforms, use ospf default bw
           if bw is configured under interface it would be used.
         */
@@ -539,6 +547,7 @@ void ospf_del_if_params(struct ospf_if_params *oip)
 {
        list_delete(&oip->auth_crypt);
        bfd_info_free(&(oip->bfd_info));
+       ldp_sync_info_free(&(oip->ldp_sync_info));
        XFREE(MTYPE_OSPF_IF_PARAMS, oip);
 }
 
index 4b3dbcc5c27284e4fe1c051e6676f373a035874c..1d28eac6b3f660d3b08fe202f12cd76068879542 100644 (file)
@@ -104,6 +104,9 @@ struct ospf_if_params {
 
        /* BFD configuration */
        struct bfd_info *bfd_info;
+
+       /* MPLS LDP-IGP Sync configuration */
+       struct ldp_sync_info *ldp_sync_info;
 };
 
 enum { MEMBER_ALLROUTERS = 0,
diff --git a/ospfd/ospf_ldp_sync.c b/ospfd/ospf_ldp_sync.c
new file mode 100644 (file)
index 0000000..a8c9df1
--- /dev/null
@@ -0,0 +1,1142 @@
+/*
+ * ospf_ldp_sync.c: OSPF 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 "ospfd.h"
+#include "ospf_interface.h"
+#include "ospf_vty.h"
+#include "ospf_ldp_sync.h"
+#include "ospf_dump.h"
+#include "ospf_ism.h"
+
+extern struct zclient *zclient;
+
+/*
+ * LDP-SYNC msg between IGP and LDP
+ */
+int ospf_ldp_sync_state_update(struct ldp_igp_sync_if_state state)
+{
+       struct ospf *ospf;
+       struct interface *ifp;
+
+       /* if ospf is not enabled or LDP-SYNC is not configured ignore */
+       ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
+       if (ospf == NULL ||
+           !CHECK_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
+               return 0;
+
+       /* received ldp-sync interface state from LDP */
+       ifp = if_lookup_by_index(state.ifindex, VRF_DEFAULT);
+       if (ifp == NULL || if_is_loopback(ifp))
+               return 0;
+
+       ols_debug("ldp_sync: rcvd %s from LDP if %s",
+                 state.sync_start ? "sync-start" : "sync-complete",
+                 ifp->name);
+       if (state.sync_start)
+               ospf_ldp_sync_if_start(ifp, false);
+       else
+               ospf_ldp_sync_if_complete(ifp);
+
+       return 0;
+}
+
+int ospf_ldp_sync_announce_update(struct ldp_igp_sync_announce announce)
+{
+       struct ospf *ospf;
+       struct vrf *vrf;
+       struct interface *ifp;
+
+       /* if ospf is not enabled or LDP-SYNC is not configured ignore */
+       ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
+       if (ospf == NULL ||
+           !CHECK_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
+               return 0;
+
+       if (announce.proto != ZEBRA_ROUTE_LDP)
+               return 0;
+
+       ols_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(ospf->vrf_id);
+       FOR_ALL_INTERFACES (vrf, ifp)
+               ospf_ldp_sync_if_start(ifp, true);
+
+       THREAD_TIMER_OFF(ospf->ldp_sync_cmd.t_hello);
+       ospf->ldp_sync_cmd.t_hello = NULL;
+       ospf->ldp_sync_cmd.sequence = 0;
+       ospf_ldp_sync_hello_timer_add(ospf);
+
+       return 0;
+}
+
+int ospf_ldp_sync_hello_update(struct ldp_igp_sync_hello hello)
+{
+       struct ospf *ospf;
+       struct vrf *vrf;
+       struct interface *ifp;
+
+       /* if ospf is not enabled or LDP-SYNC is not configured ignore */
+       ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
+       if (ospf == NULL ||
+           !CHECK_FLAG(ospf->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 */
+               ospf->ldp_sync_cmd.sequence = 0;
+
+       if (ospf->ldp_sync_cmd.sequence > hello.sequence) {
+               zlog_err("ldp_sync: LDP restarted");
+
+               vrf = vrf_lookup_by_id(ospf->vrf_id);
+               FOR_ALL_INTERFACES (vrf, ifp)
+                       ospf_ldp_sync_if_start(ifp, true);
+       } else {
+               THREAD_TIMER_OFF(ospf->ldp_sync_cmd.t_hello);
+               ospf_ldp_sync_hello_timer_add(ospf);
+       }
+       ospf->ldp_sync_cmd.sequence = hello.sequence;
+
+       return 0;
+}
+
+void ospf_ldp_sync_state_req_msg(struct interface *ifp)
+{
+       struct ldp_igp_sync_if_state_req request;
+
+       ols_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 ospf_ldp_sync_if_init(struct ospf_interface *oi)
+{
+       struct ospf_if_params *params;
+       struct ldp_sync_info *ldp_sync_info;
+       struct interface *ifp = oi->ifp;
+
+       /* called when OSPF is configured on an interface:
+        *  if LDP-IGP Sync is configured globally set state
+        *  if ptop interface inform LDP LDP-SYNC is enabled
+        */
+       if (if_is_loopback(ifp) || (ifp->vrf_id != VRF_DEFAULT) ||
+           !(CHECK_FLAG(oi->ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)))
+               return;
+
+       ols_debug("ldp_sync: init if %s",ifp->name);
+       params = IF_DEF_PARAMS(ifp);
+       if (params->ldp_sync_info == NULL)
+               params->ldp_sync_info = ldp_sync_info_create();
+
+       ldp_sync_info = params->ldp_sync_info;
+
+       /* specifed on interface overrides global config. */
+       if (!CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN))
+               ldp_sync_info->holddown = oi->ospf->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 ((params->type == OSPF_IFTYPE_POINTOPOINT ||
+            if_is_pointopoint(ifp)) &&
+           ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED)
+               ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
+}
+
+void ospf_ldp_sync_if_start(struct interface *ifp, bool send_state_req)
+{
+       struct ospf_if_params *params;
+       struct ldp_sync_info *ldp_sync_info;
+
+       if (if_is_loopback(ifp))
+               return;
+
+       params = IF_DEF_PARAMS(ifp);
+       ldp_sync_info = params->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) {
+               ols_debug("ldp_sync: start on if %s state: %s",
+                         ifp->name, "Holding down until Sync");
+               ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
+               ospf_if_recalculate_output_cost(ifp);
+               ospf_ldp_sync_holddown_timer_add(ifp);
+
+               if (send_state_req)
+                       ospf_ldp_sync_state_req_msg(ifp);
+       }
+}
+
+void ospf_ldp_sync_if_complete(struct interface *ifp)
+{
+       struct ospf_if_params *params;
+       struct ldp_sync_info *ldp_sync_info;
+
+       if (if_is_loopback(ifp))
+               return;
+
+       params = IF_DEF_PARAMS(ifp);
+       ldp_sync_info = params->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;
+               ospf_if_recalculate_output_cost(ifp);
+       }
+}
+
+void ospf_ldp_sync_ldp_fail(struct interface *ifp)
+{
+       struct ospf_if_params *params;
+       struct ldp_sync_info *ldp_sync_info;
+
+       if (if_is_loopback(ifp))
+               return;
+
+       params = IF_DEF_PARAMS(ifp);
+       ldp_sync_info = params->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 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;
+               ospf_if_recalculate_output_cost(ifp);
+       }
+}
+
+void ospf_ldp_sync_if_down(struct interface *ifp)
+{
+       struct ospf_if_params *params;
+       struct ldp_sync_info *ldp_sync_info;
+
+       if (if_is_loopback(ifp))
+               return;
+
+       params = IF_DEF_PARAMS(ifp);
+       ldp_sync_info = params->ldp_sync_info;
+
+       if (ldp_sync_if_down(ldp_sync_info) == false)
+               return;
+
+       ols_debug("ldp_sync: down on if %s", ifp->name);
+
+       /* Interface down:
+        *  can occur from a link down or changing config
+        *  ospf network type change interface is brought down/up
+        */
+       switch (ldp_sync_info->state) {
+       case LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP:
+       case LDP_IGP_SYNC_STATE_REQUIRED_UP:
+               if (params->type != OSPF_IFTYPE_POINTOPOINT &&
+                   !if_is_pointopoint(ifp))
+                       /* LDP-SYNC not able to run on non-ptop interface */
+                       ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED;
+               break;
+       case LDP_IGP_SYNC_STATE_NOT_REQUIRED:
+               if (params->type == OSPF_IFTYPE_POINTOPOINT ||
+                   if_is_pointopoint(ifp))
+                       /* LDP-SYNC is able to run on ptop interface */
+                       ldp_sync_info->state =
+                               LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
+               break;
+       default:
+               break;
+       }
+}
+
+void ospf_ldp_sync_if_remove(struct interface *ifp, bool remove)
+{
+       struct ospf_if_params *params;
+       struct ldp_sync_info *ldp_sync_info;
+
+       params = IF_DEF_PARAMS(ifp);
+       if (params->ldp_sync_info == NULL)
+               return;
+
+       ldp_sync_info = params->ldp_sync_info;
+
+       /* Stop LDP-SYNC on this interface:
+        *  if holddown timer is running stop it
+        *  delete ldp instance on interface
+        *  restore cost
+        */
+       ols_debug("ldp_sync: Removed from if %s", ifp->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;
+       ospf_if_recalculate_output_cost(ifp);
+       if (!CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG))
+               ldp_sync_info->enabled = LDP_IGP_SYNC_DEFAULT;
+       if (remove) {
+               ldp_sync_info_free((struct ldp_sync_info **)&(ldp_sync_info));
+               params->ldp_sync_info = NULL;
+       }
+}
+
+static int ospf_ldp_sync_ism_change(struct ospf_interface *oi, int state,
+                                   int old_state)
+{
+       /* Terminal state or regression */
+       switch (state) {
+       case ISM_PointToPoint:
+               /* If LDP-SYNC is configure on interface then start */
+               ospf_ldp_sync_if_start(oi->ifp, true);
+               break;
+       case ISM_Down:
+               /* If LDP-SYNC is configure on this interface then stop it */
+               ospf_ldp_sync_if_down(oi->ifp);
+               break;
+       default:
+               break;
+       }
+       return 0;
+}
+
+/*
+ * LDP-SYNC holddown timer routines
+ */
+static int ospf_ldp_sync_holddown_timer(struct thread *thread)
+{
+       struct interface *ifp;
+       struct ospf_if_params *params;
+       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
+        */
+       ifp = THREAD_ARG(thread);
+       params = IF_DEF_PARAMS(ifp);
+       if (params->ldp_sync_info) {
+               ldp_sync_info = params->ldp_sync_info;
+
+               ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_UP;
+               ldp_sync_info->t_holddown = NULL;
+
+               ols_debug("ldp_sync: holddown timer expired for %s state: %s",
+                         ifp->name, "Sync achieved");
+
+               ospf_if_recalculate_output_cost(ifp);
+       }
+       return 0;
+}
+
+void ospf_ldp_sync_holddown_timer_add(struct interface *ifp)
+{
+       struct ospf_if_params *params;
+       struct ldp_sync_info *ldp_sync_info;
+
+       params = IF_DEF_PARAMS(ifp);
+       ldp_sync_info = params->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;
+
+       ols_debug("ldp_sync: start holddown timer for %s time %d",
+                 ifp->name, ldp_sync_info->holddown);
+
+       thread_add_timer(master, ospf_ldp_sync_holddown_timer,
+                        ifp, ldp_sync_info->holddown,
+                        &ldp_sync_info->t_holddown);
+}
+
+/*
+ * LDP-SYNC hello timer routines
+ */
+static int ospf_ldp_sync_hello_timer(struct thread *thread)
+{
+       struct ospf *ospf;
+       struct vrf *vrf;
+       struct interface *ifp;
+
+       /* hello timer expired:
+        *  didn't receive hello msg from LDP
+        *  set cost of all interfaces to LSInfinity
+        */
+       ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
+       if (ospf) {
+               ospf->ldp_sync_cmd.t_hello = NULL;
+               vrf = vrf_lookup_by_id(ospf->vrf_id);
+
+               FOR_ALL_INTERFACES (vrf, ifp)
+                       ospf_ldp_sync_ldp_fail(ifp);
+
+               zlog_err("ldp_sync: hello timer expired, LDP down");
+       }
+       return 0;
+}
+
+void ospf_ldp_sync_hello_timer_add(struct ospf *ospf)
+{
+
+       /* Start hello timer:
+        *  this timer is used to make sure LDP is up
+        *  if expires set interface cost to LSInfinity
+        */
+       if (!CHECK_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
+               return;
+
+       thread_add_timer(master, ospf_ldp_sync_hello_timer,
+                        NULL, LDP_IGP_SYNC_HELLO_TIMEOUT,
+                        &ospf->ldp_sync_cmd.t_hello);
+}
+
+/*
+ * LDP-SYNC exit routes.
+ */
+void ospf_ldp_sync_gbl_exit(struct ospf *ospf, bool remove)
+{
+       struct interface *ifp;
+       struct vrf *vrf;
+
+       /* ospf is being removed
+        *  stop hello timer
+        *  stop any holddown timers
+        */
+       if (CHECK_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) {
+               /* unregister 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 globally */
+               UNSET_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE);
+               UNSET_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN);
+               ospf->ldp_sync_cmd.holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT;
+               THREAD_TIMER_OFF(ospf->ldp_sync_cmd.t_hello);
+               ospf->ldp_sync_cmd.t_hello = NULL;
+
+               /* turn off LDP-IGP Sync on all OSPF interfaces */
+               vrf = vrf_lookup_by_id(ospf->vrf_id);
+               FOR_ALL_INTERFACES (vrf, ifp)
+                       ospf_ldp_sync_if_remove(ifp, remove);
+       }
+}
+
+/*
+ * LDP-SYNC routes used by set commands.
+ */
+void ospf_if_set_ldp_sync_enable(struct ospf *ospf, struct interface *ifp)
+{
+       struct ospf_if_params *params;
+       struct ldp_sync_info *ldp_sync_info;
+
+       /* 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 (if_is_loopback(ifp))
+               return;
+
+       params = IF_DEF_PARAMS(ifp);
+       if (params->ldp_sync_info == NULL)
+               params->ldp_sync_info = ldp_sync_info_create();
+       ldp_sync_info = params->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;
+
+       ols_debug("ldp_sync: enable if %s", ifp->name);
+
+       /* send message to LDP if ptop link */
+       if (params->type == OSPF_IFTYPE_POINTOPOINT ||
+           if_is_pointopoint(ifp)) {
+               ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
+               ospf_ldp_sync_state_req_msg(ifp);
+       } else {
+               ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED;
+               zlog_debug("ldp_sync: Sync only runs on P2P links %s",
+                          ifp->name);
+       }
+}
+
+void ospf_if_set_ldp_sync_holddown(struct ospf *ospf, struct interface *ifp)
+{
+       struct ospf_if_params *params;
+       struct ldp_sync_info *ldp_sync_info;
+
+       /* called when setting LDP-SYNC at the global level:
+        *  specifed on interface overrides global config.
+        */
+       if (if_is_loopback(ifp))
+               return;
+
+       params = IF_DEF_PARAMS(ifp);
+       if (params->ldp_sync_info == NULL)
+               params->ldp_sync_info = ldp_sync_info_create();
+       ldp_sync_info = params->ldp_sync_info;
+
+       /* config on interface, overrides global config. */
+       if (CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN))
+               return;
+       if (CHECK_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN))
+               ldp_sync_info->holddown = ospf->ldp_sync_cmd.holddown;
+       else
+               ldp_sync_info->holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT;
+}
+
+/*
+ * LDP-SYNC routines used by show commands.
+ */
+
+void ospf_ldp_sync_show_info(struct vty *vty, struct ospf *ospf,
+                            json_object *json_vrf, bool use_json)
+{
+
+       if (CHECK_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) {
+               if (use_json) {
+                       json_object_boolean_true_add(json_vrf,
+                                                    "MplsLdpIgpSyncEnabled");
+                       json_object_int_add(json_vrf, "MplsLdpIgpSyncHolddown",
+                                           ospf->ldp_sync_cmd.holddown);
+               } else {
+                       vty_out(vty, " MPLS LDP-IGP Sync is enabled\n");
+                       if (ospf->ldp_sync_cmd.holddown == 0)
+                               vty_out(vty,
+                                       " MPLS LDP-IGP Sync holddown timer is disabled\n");
+                       else
+                               vty_out(vty,
+                                       " MPLS LDP-IGP Sync holddown timer %d sec\n",
+                                       ospf->ldp_sync_cmd.holddown);
+               }
+       }
+}
+
+static void show_ip_ospf_mpls_ldp_interface_sub(struct vty *vty,
+                                              struct ospf_interface *oi,
+                                              struct interface *ifp,
+                                              json_object *json_interface_sub,
+                                              bool use_json)
+{
+       const char *ldp_state;
+       struct ospf_if_params *params;
+       char timebuf[OSPF_TIME_DUMP_SIZE];
+       struct ldp_sync_info *ldp_sync_info;
+
+       params = IF_DEF_PARAMS(oi->ifp);
+       if (params->ldp_sync_info == NULL)
+               return;
+
+       ldp_sync_info = params->ldp_sync_info;
+       if (use_json) {
+               if (ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED)
+                       json_object_boolean_true_add(json_interface_sub,
+                                                    "ldpIgpSyncEnabled");
+               else
+                       json_object_boolean_false_add(json_interface_sub,
+                                                    "ldpIgpSyncEnabled");
+
+               json_object_int_add(json_interface_sub, "holdDownTimeInSec",
+                                   ldp_sync_info->holddown);
+
+       } else {
+               vty_out(vty, "%-10s\n", ifp->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:
+               if (use_json)
+                       json_object_string_add(json_interface_sub,
+                                              "ldpIgpSyncState",
+                                              "Sync achieved");
+               else
+                       vty_out(vty, "  State: Sync achieved\n");
+               break;
+       case LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP:
+               if (ldp_sync_info->t_holddown != NULL) {
+                       if (use_json) {
+                               long time_store;
+
+                               time_store = monotime_until(
+                                       &ldp_sync_info->t_holddown->u.sands,
+                                       NULL)
+                                       /1000LL;
+
+                               json_object_int_add(json_interface_sub,
+                                                   "ldpIgpSyncTimeRemainInMsec",
+                                                   time_store);
+
+                               json_object_string_add(json_interface_sub,
+                                                      "ldpIgpSyncState",
+                                                      "Holding down until Sync");
+                       } else {
+                               vty_out(vty,
+                                       "  Holddown timer is running %s remaining\n",
+                                       ospf_timer_dump(
+                                               ldp_sync_info->t_holddown,
+                                               timebuf,
+                                               sizeof(timebuf)));
+
+                               vty_out(vty,
+                                       "  State: Holding down until Sync\n");
+                       }
+               } else {
+                       if (use_json)
+                               json_object_string_add(json_interface_sub,
+                                                      "ldpIgpSyncState",
+                                                      "Sync not achieved");
+                       else
+                               vty_out(vty, "  State: Sync not achieved\n");
+               }
+               break;
+       case LDP_IGP_SYNC_STATE_NOT_REQUIRED:
+       default:
+               if (IF_DEF_PARAMS(ifp)->type != OSPF_IFTYPE_POINTOPOINT &&
+                   !if_is_pointopoint(ifp))
+                       ldp_state = "Sync not required: non-p2p link";
+               else
+                       ldp_state = "Sync not required";
+
+               if (use_json)
+                       json_object_string_add(json_interface_sub,
+                                              "ldpIgpSyncState",
+                                              ldp_state);
+               else
+                       vty_out(vty, "  State: %s\n", ldp_state);
+               break;
+       }
+}
+
+static int show_ip_ospf_mpls_ldp_interface_common(struct vty *vty,
+                                                 struct ospf *ospf,
+                                                 char *intf_name,
+                                                 json_object *json,
+                                                 bool use_json)
+{
+       struct interface *ifp;
+       struct vrf *vrf = vrf_lookup_by_id(ospf->vrf_id);
+       json_object *json_interface_sub = NULL;
+
+       if (intf_name == NULL) {
+               /* Show All Interfaces.*/
+               FOR_ALL_INTERFACES (vrf, ifp) {
+                       struct route_node *rn;
+                       struct ospf_interface *oi;
+
+                       if (ospf_oi_count(ifp) == 0)
+                               continue;
+                       for (rn = route_top(IF_OIFS(ifp)); rn;
+                            rn = route_next(rn)) {
+                               oi = rn->info;
+
+                               if (use_json) {
+                                       json_interface_sub =
+                                               json_object_new_object();
+                               }
+                               show_ip_ospf_mpls_ldp_interface_sub(
+                                       vty, oi, ifp, json_interface_sub,
+                                       use_json);
+
+                               if (use_json) {
+                                       json_object_object_add(
+                                               json, ifp->name,
+                                               json_interface_sub);
+                               }
+                       }
+               }
+       } else {
+               /* Interface name is specified. */
+               ifp = if_lookup_by_name(intf_name, ospf->vrf_id);
+               if (ifp != NULL) {
+                       struct route_node *rn;
+                       struct ospf_interface *oi;
+
+                       if (ospf_oi_count(ifp) == 0 && !use_json) {
+                               vty_out(vty,
+                                       "  OSPF not enabled on this interface %s\n",
+                                       ifp->name);
+                               return CMD_SUCCESS;
+                       }
+                       for (rn = route_top(IF_OIFS(ifp)); rn;
+                            rn = route_next(rn)) {
+                               oi = rn->info;
+
+                               if (use_json)
+                                       json_interface_sub =
+                                               json_object_new_object();
+
+                               show_ip_ospf_mpls_ldp_interface_sub(
+                                       vty, oi, ifp, json_interface_sub,
+                                       use_json);
+
+                               if (use_json) {
+                                       json_object_object_add(
+                                               json,   ifp->name,
+                                               json_interface_sub);
+                               }
+                       }
+               }
+       }
+       return CMD_SUCCESS;
+}
+
+/*
+ * Write the global LDP-SYNC configuration.
+ */
+void ospf_ldp_sync_write_config(struct vty *vty, struct ospf *ospf)
+{
+       if (CHECK_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
+               vty_out(vty, " mpls ldp-sync\n");
+       if (CHECK_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN))
+               vty_out(vty, " mpls ldp-sync holddown %u\n",
+                       ospf->ldp_sync_cmd.holddown);
+}
+
+/*
+ * Write the interface LDP-SYNC configuration.
+ */
+void ospf_ldp_sync_if_write_config(struct vty *vty,
+                                  struct ospf_if_params *params)
+
+{
+       struct ldp_sync_info *ldp_sync_info;
+
+       ldp_sync_info = params->ldp_sync_info;
+       if (ldp_sync_info == NULL)
+               return;
+
+       if (CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG)) {
+               if (ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED)
+                       vty_out(vty, " ip ospf mpls ldp-sync\n");
+               else
+                       vty_out(vty, " no ip ospf mpls ldp-sync\n");
+       }
+       if (CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN))
+               vty_out(vty, " ip ospf mpls ldp-sync holddown %u\n",
+                       ldp_sync_info->holddown);
+}
+
+/*
+ * LDP-SYNC commands.
+ */
+#ifndef VTYSH_EXTRACT_PL
+#include "ospfd/ospf_ldp_sync_clippy.c"
+#endif
+
+DEFPY (ospf_mpls_ldp_sync,
+       ospf_mpls_ldp_sync_cmd,
+       "mpls ldp-sync",
+       "MPLS specific commands\n"
+       "Enable MPLS LDP-IGP Sync\n")
+{
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
+       struct vrf *vrf = vrf_lookup_by_id(ospf->vrf_id);
+       struct interface *ifp;
+
+       if (ospf->vrf_id != VRF_DEFAULT) {
+               vty_out(vty, "ldp-sync only runs on DEFAULT VRF\n");
+               return CMD_ERR_NOTHING_TODO;
+       }
+
+       /* 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(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) {
+               SET_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE);
+               /* turn on LDP-IGP Sync on all ptop OSPF interfaces */
+               FOR_ALL_INTERFACES (vrf, ifp)
+                       ospf_if_set_ldp_sync_enable(ospf, ifp);
+       }
+       return CMD_SUCCESS;
+}
+
+DEFPY (no_ospf_mpls_ldp_sync,
+       no_ospf_mpls_ldp_sync_cmd,
+       "no mpls ldp-sync",
+       NO_STR
+       "MPLS specific commands\n"
+       "Disable MPLS LDP-IGP Sync\n")
+{
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
+       ospf_ldp_sync_gbl_exit(ospf, false);
+       return CMD_SUCCESS;
+}
+
+DEFPY (ospf_mpls_ldp_sync_holddown,
+       ospf_mpls_ldp_sync_holddown_cmd,
+       "mpls ldp-sync holddown (1-10000)",
+       "MPLS specific commands\n"
+       "Enable MPLS LDP-IGP Sync\n"
+       "Set holddown timer\n"
+       "seconds\n")
+{
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
+       struct vrf *vrf = vrf_lookup_by_id(ospf->vrf_id);
+       struct interface *ifp;
+
+       if (ospf->vrf_id != VRF_DEFAULT) {
+               vty_out(vty, "ldp-sync only runs on DEFAULT VRF\n");
+               return CMD_ERR_NOTHING_TODO;
+       }
+
+       SET_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN);
+       ospf->ldp_sync_cmd.holddown = holddown;
+       /* set holddown time on all OSPF interfaces */
+       FOR_ALL_INTERFACES (vrf, ifp)
+               ospf_if_set_ldp_sync_holddown(ospf, ifp);
+
+       return CMD_SUCCESS;
+}
+
+DEFPY (no_ospf_mpls_ldp_sync_holddown,
+       no_ospf_mpls_ldp_sync_holddown_cmd,
+       "no mpls ldp-sync holddown [<(1-10000)>]",
+       NO_STR
+       "MPLS specific commands\n"
+       "Disable MPLS LDP-IGP Sync\n"
+       "holddown timer disable\n")
+{
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
+       struct vrf *vrf = vrf_lookup_by_id(ospf->vrf_id);
+       struct interface *ifp;
+
+       if (CHECK_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN)) {
+               UNSET_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN);
+               ospf->ldp_sync_cmd.holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT;
+               /* turn off holddown timer on all OSPF interfaces */
+               FOR_ALL_INTERFACES (vrf, ifp)
+                       ospf_if_set_ldp_sync_holddown(ospf, ifp);
+       }
+       return CMD_SUCCESS;
+}
+
+
+DEFPY (mpls_ldp_sync,
+       mpls_ldp_sync_cmd,
+       "ip ospf mpls ldp-sync",
+       IP_STR
+       "OSPF interface commands\n"
+       MPLS_STR
+       MPLS_LDP_SYNC_STR
+       MPLS_LDP_SYNC_STR)
+{
+       VTY_DECLVAR_CONTEXT(interface, ifp);
+       struct ospf_if_params *params;
+       struct ldp_sync_info *ldp_sync_info;
+
+       if (if_is_loopback(ifp)) {
+               vty_out(vty, "ldp-sync does not run on loopback interface\n");
+               return CMD_ERR_NOTHING_TODO;
+       }
+
+       if (ifp->vrf_id != VRF_DEFAULT) {
+               vty_out(vty, "ldp-sync only runs on DEFAULT VRF\n");
+               return CMD_ERR_NOTHING_TODO;
+       }
+
+       params = IF_DEF_PARAMS(ifp);
+       if (params->ldp_sync_info == NULL)
+               params->ldp_sync_info = ldp_sync_info_create();
+
+       ldp_sync_info = params->ldp_sync_info;
+
+       SET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG);
+       ldp_sync_info->enabled = LDP_IGP_SYNC_ENABLED;
+       if (params->type == OSPF_IFTYPE_POINTOPOINT || if_is_pointopoint(ifp)) {
+               ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
+               ospf_ldp_sync_state_req_msg(ifp);
+       } else {
+               zlog_debug("ldp_sync: only runs on P2P links %s", ifp->name);
+               ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED;
+       }
+       return CMD_SUCCESS;
+}
+
+DEFPY (no_mpls_ldp_sync,
+       no_mpls_ldp_sync_cmd,
+       "no ip ospf mpls ldp-sync",
+       NO_STR
+       IP_STR
+       "OSPF interface commands\n"
+       MPLS_STR
+       NO_MPLS_LDP_SYNC_STR)
+{
+       VTY_DECLVAR_CONTEXT(interface, ifp);
+       struct ospf_if_params *params;
+       struct ldp_sync_info *ldp_sync_info;
+
+       if (if_is_loopback(ifp)) {
+               vty_out(vty, "ldp-sync: does not run on loopback interface\n");
+               return CMD_ERR_NOTHING_TODO;
+       }
+
+       if (ifp->vrf_id != VRF_DEFAULT) {
+               vty_out(vty, "ldp-sync only runs on DEFAULT VRF\n");
+               return CMD_ERR_NOTHING_TODO;
+       }
+
+       params = IF_DEF_PARAMS(ifp);
+       if (params->ldp_sync_info == NULL)
+               params->ldp_sync_info = ldp_sync_info_create();
+
+       ldp_sync_info = params->ldp_sync_info;
+
+       /* disable LDP-SYNC on an interface
+        *  stop holddown timer if running
+        *  restore ospf cost
+        */
+       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;
+       ospf_if_recalculate_output_cost(ifp);
+
+       return CMD_SUCCESS;
+}
+
+DEFPY (mpls_ldp_sync_holddown,
+       mpls_ldp_sync_holddown_cmd,
+       "ip ospf mpls ldp-sync holddown (0-10000)",
+       IP_STR
+       "OSPF interface commands\n"
+       MPLS_STR
+       MPLS_LDP_SYNC_STR
+       "Time to wait for LDP-SYNC to occur before restoring interface cost\n"
+       "Time in seconds\n")
+{
+       VTY_DECLVAR_CONTEXT(interface, ifp);
+       struct ospf_if_params *params;
+       struct ldp_sync_info *ldp_sync_info;
+
+       if (if_is_loopback(ifp)) {
+               vty_out(vty, "ldp-sync: does not run on loopback interface\n");
+               return CMD_ERR_NOTHING_TODO;
+       }
+
+       if (ifp->vrf_id != VRF_DEFAULT) {
+               vty_out(vty, "ldp-sync only runs on DEFAULT VRF\n");
+               return CMD_ERR_NOTHING_TODO;
+       }
+
+       params = IF_DEF_PARAMS(ifp);
+       if (params->ldp_sync_info == NULL)
+               params->ldp_sync_info = ldp_sync_info_create();
+
+       ldp_sync_info = params->ldp_sync_info;
+
+       SET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN);
+       ldp_sync_info->holddown = holddown;
+
+       return CMD_SUCCESS;
+}
+
+DEFPY (no_mpls_ldp_sync_holddown,
+       no_mpls_ldp_sync_holddown_cmd,
+       "no ip ospf mpls ldp-sync holddown [<(1-10000)>]",
+       NO_STR
+       IP_STR
+       "OSPF interface commands\n"
+       MPLS_STR
+       NO_MPLS_LDP_SYNC_STR
+       NO_MPLS_LDP_SYNC_HOLDDOWN_STR)
+{
+       VTY_DECLVAR_CONTEXT(interface, ifp);
+       struct ospf_if_params *params;
+       struct ldp_sync_info *ldp_sync_info;
+       struct ospf *ospf;
+
+       if (if_is_loopback(ifp)) {
+               vty_out(vty, "ldp-sync: does not run on loopback interface\n");
+               return CMD_ERR_NOTHING_TODO;
+       }
+
+       if (ifp->vrf_id != VRF_DEFAULT) {
+               vty_out(vty, "ldp-sync only runs on DEFAULT VRF\n");
+               return CMD_ERR_NOTHING_TODO;
+       }
+
+       params = IF_DEF_PARAMS(ifp);
+       ldp_sync_info = params->ldp_sync_info;
+       if (ldp_sync_info == NULL)
+               return CMD_SUCCESS;
+
+       /* use global configured value if set */
+       if (CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN)) {
+               UNSET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN);
+               ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
+               if (ospf && CHECK_FLAG(ospf->ldp_sync_cmd.flags,
+                              LDP_SYNC_FLAG_HOLDDOWN))
+                       ldp_sync_info->holddown = ospf->ldp_sync_cmd.holddown;
+               else
+                       ldp_sync_info->holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT;
+       }
+       return CMD_SUCCESS;
+}
+
+DEFPY (show_ip_ospf_mpls_ldp_interface,
+       show_ip_ospf_mpls_ldp_interface_cmd,
+       "show ip ospf mpls ldp-sync [interface <INTERFACE|all>] [json]",
+       SHOW_STR
+       IP_STR
+       "OSPF information\n"
+       MPLS_STR
+       "LDP-IGP Sync information\n"
+       "Interface name\n"
+       JSON_STR)
+{
+       struct ospf *ospf;
+       bool uj = use_json(argc, argv);
+       char *intf_name = NULL;
+       int ret = CMD_SUCCESS;
+       int idx_intf = 0;
+       json_object *json = NULL;
+
+       if (argv_find(argv, argc, "INTERFACE", &idx_intf))
+               intf_name = argv[idx_intf]->arg;
+
+       if (uj)
+               json = json_object_new_object();
+
+       /* Display default ospf (instance 0) info */
+       ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
+       if (ospf == NULL || !ospf->oi_running) {
+               if (uj) {
+                       vty_out(vty, "%s\n", json_object_to_json_string_ext(
+                               json, JSON_C_TO_STRING_PRETTY));
+                       json_object_free(json);
+               } else
+                       vty_out(vty, "%% OSPF instance not found\n");
+               return CMD_SUCCESS;
+       }
+
+       if (!CHECK_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) {
+               if (uj) {
+                       vty_out(vty, "%s\n", json_object_to_json_string_ext(
+                               json, JSON_C_TO_STRING_PRETTY));
+                       json_object_free(json);
+               } else
+                       vty_out(vty, "LDP-sync is disabled\n");
+               return CMD_SUCCESS;
+       }
+
+       ret = show_ip_ospf_mpls_ldp_interface_common(vty, ospf, intf_name,
+                                                    json, uj);
+       if (uj) {
+               vty_out(vty, "%s\n", json_object_to_json_string_ext(
+                       json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
+
+       return ret;
+}
+
+void ospf_ldp_sync_init(void)
+{
+       /* Install global ldp-igp sync commands */
+       install_element(OSPF_NODE, &ospf_mpls_ldp_sync_cmd);
+       install_element(OSPF_NODE, &no_ospf_mpls_ldp_sync_cmd);
+       install_element(OSPF_NODE, &ospf_mpls_ldp_sync_holddown_cmd);
+       install_element(OSPF_NODE, &no_ospf_mpls_ldp_sync_holddown_cmd);
+
+       /* Interface lsp-igp sync commands */
+       install_element(INTERFACE_NODE, &mpls_ldp_sync_cmd);
+       install_element(INTERFACE_NODE, &no_mpls_ldp_sync_cmd);
+       install_element(INTERFACE_NODE, &mpls_ldp_sync_holddown_cmd);
+       install_element(INTERFACE_NODE, &no_mpls_ldp_sync_holddown_cmd);
+
+       /* "show ip ospf mpls ldp interface" commands. */
+       install_element(VIEW_NODE, &show_ip_ospf_mpls_ldp_interface_cmd);
+
+       hook_register(ospf_ism_change, ospf_ldp_sync_ism_change);
+
+}
diff --git a/ospfd/ospf_ldp_sync.h b/ospfd/ospf_ldp_sync.h
new file mode 100644 (file)
index 0000000..d4efa55
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * ospf_ldp_sync.h: OSPF 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_OSPF_LDP_SYNC_H
+#define _ZEBRA_OSPF_LDP_SYNC_H
+
+#define LDP_OSPF_LSINFINITY 65535
+
+/* Macro to log debug message */
+#define ols_debug(...)                                                         \
+       do {                                                                   \
+               if (IS_DEBUG_OSPF_LDP_SYNC)                                    \
+                       zlog_debug(__VA_ARGS__);                               \
+       } while (0)
+
+
+extern void ospf_if_set_ldp_sync_enable(struct ospf *ospf,
+                                       struct interface *ifp);
+extern void ospf_if_set_ldp_sync_holddown(struct ospf *ospf,
+                                         struct interface *ifp);
+extern void ospf_ldp_sync_if_init(struct ospf_interface *ospf);
+extern void ospf_ldp_sync_if_start(struct interface *ifp, bool send_state_req);
+extern void ospf_ldp_sync_if_remove(struct interface *ifp, bool remove);
+extern void ospf_ldp_sync_if_down(struct interface *ifp);
+extern void ospf_ldp_sync_if_complete(struct interface *ifp);
+extern void ospf_ldp_sync_holddown_timer_add(struct interface *ifp);
+extern void ospf_ldp_sync_hello_timer_add(struct ospf *ospf);
+extern void ospf_ldp_sync_ldp_fail(struct interface *ifp);
+extern void ospf_ldp_sync_show_info(struct vty *vty, struct ospf *ospf,
+                                   json_object *json_vrf, bool use_json);
+extern void ospf_ldp_sync_write_config(struct vty *vty, struct ospf *ospf);
+extern void ospf_ldp_sync_if_write_config(struct vty *vty,
+                                         struct ospf_if_params *params);
+extern int ospf_ldp_sync_state_update(struct ldp_igp_sync_if_state state);
+extern int ospf_ldp_sync_announce_update(struct ldp_igp_sync_announce announce);
+extern int ospf_ldp_sync_hello_update(struct ldp_igp_sync_hello hello);
+extern void ospf_ldp_sync_state_req_msg(struct interface *ifp);
+extern void ospf_ldp_sync_init(void);
+extern void ospf_ldp_sync_gbl_exit(struct ospf *ospf, bool remove);
+#endif /* _ZEBRA_OSPF_LDP_SYNC_H */
index 45382e48d3f77e77db49e26eda7968cb6fb53214..6be5486b55ac28c78ed25faca3e03bd2701ba11d 100644 (file)
@@ -54,6 +54,7 @@
 #include "ospfd/ospf_vty.h"
 #include "ospfd/ospf_bfd.h"
 #include "ospfd/ospf_errors.h"
+#include "ospfd/ospf_ldp_sync.h"
 
 /* ospfd privileges */
 zebra_capabilities_t _caps_p[] = {ZCAP_NET_RAW, ZCAP_BIND, ZCAP_NET_ADMIN,
@@ -217,6 +218,9 @@ int main(int argc, char **argv)
        /* OSPF BFD init */
        ospf_bfd_init();
 
+       /* OSPF LDP IGP Sync init */
+       ospf_ldp_sync_init();
+
        ospf_route_map_init();
        ospf_opaque_init();
 
index e8cc50c8d040cf0f99cc431e342209b3d1f593b7..c3c4326da8d4706cceca6760c3ff97276156dc1e 100644 (file)
@@ -52,6 +52,7 @@
 #include "ospfd/ospf_vty.h"
 #include "ospfd/ospf_dump.h"
 #include "ospfd/ospf_bfd.h"
+#include "ospfd/ospf_ldp_sync.h"
 
 FRR_CFG_DEFAULT_BOOL(OSPF_LOG_ADJACENCY_CHANGES,
        { .val_bool = true, .match_profile = "datacenter", },
@@ -3222,6 +3223,10 @@ static int show_ip_ospf_common(struct vty *vty, struct ospf *ospf,
                                vty_out(vty, " Adjacency changes are logged\n");
                }
        }
+
+       /* show LDP-Sync status */
+       ospf_ldp_sync_show_info(vty, ospf, json_vrf, json ? 1 : 0);
+
        /* Show each area status. */
        for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area))
                show_ip_ospf_area(vty, area, json_areas, json ? 1 : 0);
@@ -9950,6 +9955,9 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf)
                                vty_out(vty, "\n");
                        }
 
+                       /* LDP-Sync print */
+                       if (params && params->ldp_sync_info)
+                               ospf_ldp_sync_if_write_config(vty, params);
 
                        while (1) {
                                if (rn == NULL)
@@ -10465,6 +10473,9 @@ static int ospf_config_write_one(struct vty *vty, struct ospf *ospf)
 
        ospf_opaque_config_write_router(vty, ospf);
 
+       /* LDP-Sync print */
+       ospf_ldp_sync_write_config(vty, ospf);
+
        write++;
        return write;
 }
index 2b8769a4a87b1848fde93880ab87945041b1eb84..6020e8dbb22296621ffabff8e8d2bda0df7c5b31 100644 (file)
@@ -51,6 +51,7 @@
 #include "ospfd/ospf_zebra.h"
 #include "ospfd/ospf_te.h"
 #include "ospfd/ospf_sr.h"
+#include "ospfd/ospf_ldp_sync.h"
 
 DEFINE_MTYPE_STATIC(OSPFD, OSPF_EXTERNAL, "OSPF External route table")
 DEFINE_MTYPE_STATIC(OSPFD, OSPF_REDISTRIBUTE, "OSPF Redistriute")
@@ -1721,6 +1722,45 @@ static void ospf_zebra_connected(struct zclient *zclient)
        zclient_send_reg_requests(zclient, VRF_DEFAULT);
 }
 
+/*
+ * opaque messages between processes
+ */
+static int ospf_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 = ospf_ldp_sync_state_update(state);
+               break;
+       case LDP_IGP_SYNC_ANNOUNCE_UPDATE:
+               STREAM_GET(&announce, s, sizeof(announce));
+               ret = ospf_ldp_sync_announce_update(announce);
+               break;
+       case LDP_IGP_SYNC_HELLO_UPDATE:
+               STREAM_GET(&hello, s, sizeof(hello));
+               ret = ospf_ldp_sync_hello_update(hello);
+               break;
+       default:
+               break;
+       }
+
+stream_failure:
+
+       return ret;
+}
+
 void ospf_zebra_init(struct thread_master *master, unsigned short instance)
 {
        /* Allocate zebra structure. */
@@ -1740,6 +1780,8 @@ void ospf_zebra_init(struct thread_master *master, unsigned short instance)
        access_list_delete_hook(ospf_filter_update);
        prefix_list_add_hook(ospf_prefix_list_update);
        prefix_list_delete_hook(ospf_prefix_list_update);
+
+       zclient->opaque_msg_handler = ospf_opaque_msg_handler;
 }
 
 void ospf_zebra_send_arp(const struct interface *ifp, const struct prefix *p)
index f9cc474d5c4059c39c8293c7feb1cc5b359af132..cdd1c6a934e5a78d5968fbcfc52ecbf677859472 100644 (file)
@@ -39,6 +39,7 @@
 #include "libfrr.h"
 #include "defaults.h"
 #include "lib_errors.h"
+#include "ldp_sync.h"
 
 #include "ospfd/ospfd.h"
 #include "ospfd/ospf_network.h"
@@ -57,6 +58,7 @@
 #include "ospfd/ospf_abr.h"
 #include "ospfd/ospf_flood.h"
 #include "ospfd/ospf_ase.h"
+#include "ospfd/ospf_ldp_sync.h"
 
 
 DEFINE_QOBJ_TYPE(ospf)
@@ -617,6 +619,10 @@ static void ospf_finish_final(struct ospf *ospf)
 
        list_delete(&ospf->vlinks);
 
+       /* shutdown LDP-Sync */
+       if (ospf->vrf_id == VRF_DEFAULT)
+               ospf_ldp_sync_gbl_exit(ospf, true);
+
        /* Remove any ospf interface config params */
        FOR_ALL_INTERFACES (vrf, ifp) {
                struct ospf_if_params *params;
@@ -946,6 +952,9 @@ static void add_ospf_interface(struct connected *co, struct ospf_area *area)
 
        ospf_area_add_if(oi->area, oi);
 
+       /* if LDP-IGP Sync is configured globally inherit config */
+       ospf_ldp_sync_if_init(oi);
+
        /*
         * if router_id is not configured, dont bring up
         * interfaces.
index cdeaa38dc0c3ae26ae53c4ed7e170d461c1b9667..20922afea3271f53c9c1f73c628e48d4e8e90bac 100644 (file)
@@ -25,6 +25,7 @@
 #include <zebra.h>
 #include "qobj.h"
 #include "libospf.h"
+#include "ldp_sync.h"
 
 #include "filter.h"
 #include "log.h"
@@ -316,6 +317,9 @@ struct ospf {
        struct list *external[ZEBRA_ROUTE_MAX + 1];
 #define EXTERNAL_INFO(E)      (E->external_info)
 
+       /* MPLS LDP-IGP Sync */
+       struct ldp_sync_info_cmd ldp_sync_cmd;
+
        QOBJ_FIELDS
 };
 DECLARE_QOBJ_TYPE(ospf)
index 447ddf9cbbbad76084bee909ce68c73b28a6ab1a..236b76a1f7ba1aa57a70b863b34ee9602853152a 100644 (file)
@@ -9,6 +9,7 @@ dist_examples_DATA += ospfd/ospfd.conf.sample
 vtysh_scan += \
        ospfd/ospf_bfd.c \
        ospfd/ospf_dump.c \
+       ospfd/ospf_ldp_sync.c \
        ospfd/ospf_opaque.c \
        ospfd/ospf_ri.c \
        ospfd/ospf_routemap.c \
@@ -37,6 +38,7 @@ ospfd_libfrrospf_a_SOURCES = \
        ospfd/ospf_ia.c \
        ospfd/ospf_interface.c \
        ospfd/ospf_ism.c \
+       ospfd/ospf_ldp_sync.c \
        ospfd/ospf_lsa.c \
        ospfd/ospf_lsdb.c \
        ospfd/ospf_memory.c \
@@ -74,6 +76,7 @@ endif
 
 clippy_scan += \
        ospfd/ospf_vty.c \
+       ospfd/ospf_ldp_sync.c \
        # end
 
 noinst_HEADERS += \
@@ -86,6 +89,7 @@ noinst_HEADERS += \
        ospfd/ospf_flood.h \
        ospfd/ospf_ia.h \
        ospfd/ospf_interface.h \
+       ospfd/ospf_ldp_sync.h \
        ospfd/ospf_memory.h \
        ospfd/ospf_neighbor.h \
        ospfd/ospf_network.h \