frr/ospfd/ospf_ldp_sync.c

1073 lines
29 KiB
C

/*
* 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("%s: rcvd %s from LDP if %s", __func__,
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("%s: rcvd announce from LDP", __func__);
/* LDP just started up:
* set cost to LSInfinity
* send request to LDP for LDP-SYNC state for each interface
*/
vrf = vrf_lookup_by_id(ospf->vrf_id);
FOR_ALL_INTERFACES (vrf, ifp)
ospf_ldp_sync_if_start(ifp, true);
return 0;
}
void ospf_ldp_sync_state_req_msg(struct interface *ifp)
{
struct ldp_igp_sync_if_state_req request;
ols_debug("%s: send state request to LDP for %s", __func__, ifp->name);
memset(&request, 0, sizeof(request));
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->vrf_id != VRF_DEFAULT)
|| !(CHECK_FLAG(oi->ospf->ldp_sync_cmd.flags,
LDP_SYNC_FLAG_ENABLE)))
return;
ols_debug("%s: init if %s", __func__, 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;
/* specified 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("%s: start on if %s state: %s", __func__, 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_OFF(ldp_sync_info->t_holddown);
ospf_if_recalculate_output_cost(ifp);
}
}
void ospf_ldp_sync_handle_client_close(struct zapi_client_close_info *info)
{
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;
/* Check if the LDP main client session closed */
if (info->proto != ZEBRA_ROUTE_LDP || info->session_id == 0)
return;
/* Handle the zebra notification that the LDP client session closed.
* set cost to LSInfinity
* send request to LDP for LDP-SYNC state for each interface
*/
zlog_err("%s: LDP down", __func__);
vrf = vrf_lookup_by_id(ospf->vrf_id);
FOR_ALL_INTERFACES (vrf, ifp)
ospf_ldp_sync_ldp_fail(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 client close detected:
* 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) {
THREAD_OFF(ldp_sync_info->t_holddown);
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("%s: down on if %s", __func__, 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("%s: Removed from if %s", __func__, ifp->name);
THREAD_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(&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 void 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;
ols_debug("%s: holddown timer expired for %s state: %s",
__func__, ifp->name, "Sync achieved");
ospf_if_recalculate_output_cost(ifp);
}
}
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("%s: start holddown timer for %s time %d", __func__,
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 exit routes.
*/
void ospf_ldp_sync_gbl_exit(struct ospf *ospf, bool remove)
{
struct interface *ifp;
struct vrf *vrf;
/* ospf is being removed
* 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);
/* 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;
/* 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:
* specified 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("%s: enable if %s", __func__, 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("%s: Sync only runs on P2P links %s", __func__,
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:
* specified 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 && !use_json) {
if (!if_is_up(ifp))
vty_out(vty, "%s\n Interface down\n",
ifp->name);
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) {
if (if_is_up(ifp))
vty_out(vty, "%s\n OSPF not enabled\n",
ifp->name);
else
vty_out(vty, "%s\n Interface down\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.
*/
#include "ospfd/ospf_ldp_sync_clippy.c"
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);
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"
"Time in seconds\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)
{
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->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->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_OFF(ldp_sync_info->t_holddown);
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->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
"Time in seconds\n")
{
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->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 information\n"
"Interface name\n"
"All interfaces\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_json(vty, 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_json(vty, 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_json(vty, 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);
}