summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlynne <lynne@voltanet.io>2020-07-22 19:31:14 +0200
committerlynne <lynne@voltanet.io>2020-09-09 20:38:44 +0200
commit132a782eb829931aa41482393e83ab253f2ed3c9 (patch)
tree05a155bed0a814231fdba1d996a0d0e7acba8500
parentlib: adding support for LDP IGP Sync feature (diff)
downloadfrr-132a782eb829931aa41482393e83ab253f2ed3c9.tar.xz
frr-132a782eb829931aa41482393e83ab253f2ed3c9.zip
ospfd: ldp-igp-sync feature: adding ospf support
Signed-off-by: Lynne Morrison <lynne@voltanet.io> Signed-off-by: Karen Schoener <karen@voltanet.io>
-rw-r--r--ospfd/ospf_dump.c43
-rw-r--r--ospfd/ospf_dump.h4
-rw-r--r--ospfd/ospf_interface.c9
-rw-r--r--ospfd/ospf_interface.h3
-rw-r--r--ospfd/ospf_ldp_sync.c1142
-rw-r--r--ospfd/ospf_ldp_sync.h56
-rw-r--r--ospfd/ospf_main.c4
-rw-r--r--ospfd/ospf_vty.c11
-rw-r--r--ospfd/ospf_zebra.c42
-rw-r--r--ospfd/ospfd.c9
-rw-r--r--ospfd/ospfd.h4
-rw-r--r--ospfd/subdir.am4
12 files changed, 1331 insertions, 0 deletions
diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c
index dcc479def..e8798e023 100644
--- a/ospfd/ospf_dump.c
+++ b/ospfd/ospf_dump.c
@@ -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);
diff --git a/ospfd/ospf_dump.h b/ospfd/ospf_dump.h
index 8c01977ff..faae27e2c 100644
--- a/ospfd/ospf_dump.h
+++ b/ospfd/ospf_dump.h
@@ -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)
@@ -107,6 +108,8 @@
#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[];
diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c
index 7977a2a9f..d9845f6eb 100644
--- a/ospfd/ospf_interface.c
+++ b/ospfd/ospf_interface.c
@@ -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);
}
diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h
index 4b3dbcc5c..1d28eac6b 100644
--- a/ospfd/ospf_interface.h
+++ b/ospfd/ospf_interface.h
@@ -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
index 000000000..a8c9df1c5
--- /dev/null
+++ b/ospfd/ospf_ldp_sync.c
@@ -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
index 000000000..d4efa5531
--- /dev/null
+++ b/ospfd/ospf_ldp_sync.h
@@ -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 */
diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c
index 45382e48d..6be5486b5 100644
--- a/ospfd/ospf_main.c
+++ b/ospfd/ospf_main.c
@@ -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();
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index e8cc50c8d..c3c4326da 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -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;
}
diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c
index 2b8769a4a..6020e8dbb 100644
--- a/ospfd/ospf_zebra.c
+++ b/ospfd/ospf_zebra.c
@@ -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)
diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c
index f9cc474d5..cdd1c6a93 100644
--- a/ospfd/ospfd.c
+++ b/ospfd/ospfd.c
@@ -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.
diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h
index cdeaa38dc..20922afea 100644
--- a/ospfd/ospfd.h
+++ b/ospfd/ospfd.h
@@ -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)
diff --git a/ospfd/subdir.am b/ospfd/subdir.am
index 447ddf9cb..236b76a1f 100644
--- a/ospfd/subdir.am
+++ b/ospfd/subdir.am
@@ -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 \