diff options
author | lynne <lynne@voltanet.io> | 2020-07-22 19:31:14 +0200 |
---|---|---|
committer | lynne <lynne@voltanet.io> | 2020-09-09 20:38:44 +0200 |
commit | 132a782eb829931aa41482393e83ab253f2ed3c9 (patch) | |
tree | 05a155bed0a814231fdba1d996a0d0e7acba8500 | |
parent | lib: adding support for LDP IGP Sync feature (diff) | |
download | frr-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.c | 43 | ||||
-rw-r--r-- | ospfd/ospf_dump.h | 4 | ||||
-rw-r--r-- | ospfd/ospf_interface.c | 9 | ||||
-rw-r--r-- | ospfd/ospf_interface.h | 3 | ||||
-rw-r--r-- | ospfd/ospf_ldp_sync.c | 1142 | ||||
-rw-r--r-- | ospfd/ospf_ldp_sync.h | 56 | ||||
-rw-r--r-- | ospfd/ospf_main.c | 4 | ||||
-rw-r--r-- | ospfd/ospf_vty.c | 11 | ||||
-rw-r--r-- | ospfd/ospf_zebra.c | 42 | ||||
-rw-r--r-- | ospfd/ospfd.c | 9 | ||||
-rw-r--r-- | ospfd/ospfd.h | 4 | ||||
-rw-r--r-- | ospfd/subdir.am | 4 |
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 \ |