Merge pull request #6789 from volta-networks/feat_ldp_igp_sync

ldpd: Add support for LDP-IGP Synchronization
This commit is contained in:
Renato Westphal 2020-09-11 15:55:04 -03:00 committed by GitHub
commit beb91114ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
170 changed files with 8049 additions and 18 deletions

View File

@ -59,6 +59,7 @@
#include "isisd/isis_errors.h"
#include "isisd/isis_tx_queue.h"
#include "isisd/isis_nb.h"
#include "isisd/isis_ldp_sync.h"
DEFINE_QOBJ_TYPE(isis_circuit)
@ -1280,6 +1281,7 @@ struct isis_circuit *isis_circuit_create(struct isis_area *area,
isis_circuit_if_bind(circuit, ifp);
if (circuit->area->mta && circuit->area->mta->status)
isis_link_params_update(circuit, ifp);
return circuit;
}
@ -1350,11 +1352,16 @@ ferr_r isis_circuit_metric_set(struct isis_circuit *circuit, int level,
return ferr_cfg_invalid("metric %d too large for narrow metric",
metric);
circuit->te_metric[level - 1] = metric;
circuit->metric[level - 1] = metric;
if (circuit->area)
lsp_regenerate_schedule(circuit->area, level, 0);
/* inform ldp-sync of metric change
* if ldp-sync is running need to save metric
* and restore new values after ldp-sync completion.
*/
if (isis_ldp_sync_if_metric_config(circuit, level, metric)) {
circuit->te_metric[level - 1] = metric;
circuit->metric[level - 1] = metric;
if (circuit->area)
lsp_regenerate_schedule(circuit->area, level, 0);
}
return ferr_ok();
}

View File

@ -139,6 +139,7 @@ struct isis_circuit {
uint8_t flags;
bool disable_threeway_adj;
struct bfd_info *bfd_info;
struct ldp_sync_info *ldp_sync_info;
/*
* Counters as in 10589--11.2.5.9
*/

View File

@ -2386,6 +2386,178 @@ void cli_show_isis_log_adjacency(struct vty *vty, struct lyd_node *dnode,
vty_out(vty, " log-adjacency-changes\n");
}
/*
* XPath: /frr-isisd:isis/instance/mpls/ldp-sync
*/
DEFPY(isis_mpls_ldp_sync, isis_mpls_ldp_sync_cmd, "mpls ldp-sync",
MPLS_STR MPLS_LDP_SYNC_STR)
{
nb_cli_enqueue_change(vty, "./mpls/ldp-sync", NB_OP_CREATE, NULL);
return nb_cli_apply_changes(vty, NULL);
}
DEFPY(no_isis_mpls_ldp_sync, no_isis_mpls_ldp_sync_cmd, "no mpls ldp-sync",
NO_STR MPLS_STR NO_MPLS_LDP_SYNC_STR)
{
nb_cli_enqueue_change(vty, "./mpls/ldp-sync", NB_OP_DESTROY, NULL);
return nb_cli_apply_changes(vty, NULL);
}
void cli_show_isis_mpls_ldp_sync(struct vty *vty, struct lyd_node *dnode,
bool show_defaults)
{
vty_out(vty, " mpls ldp-sync\n");
}
DEFPY(isis_mpls_ldp_sync_holddown, isis_mpls_ldp_sync_holddown_cmd,
"mpls ldp-sync holddown (0-10000)",
MPLS_STR MPLS_LDP_SYNC_STR
"Time to wait for LDP-SYNC to occur before restoring interface metric\n"
"Time in seconds\n")
{
nb_cli_enqueue_change(vty, "./mpls/ldp-sync/holddown", NB_OP_MODIFY,
holddown_str);
return nb_cli_apply_changes(vty, NULL);
}
DEFPY(no_isis_mpls_ldp_sync_holddown, no_isis_mpls_ldp_sync_holddown_cmd,
"no mpls ldp-sync holddown [<(1-10000)>]",
NO_STR MPLS_STR MPLS_LDP_SYNC_STR NO_MPLS_LDP_SYNC_HOLDDOWN_STR)
{
nb_cli_enqueue_change(vty, "./mpls/ldp-sync/holddown", NB_OP_DESTROY,
NULL);
return nb_cli_apply_changes(vty, NULL);
}
void cli_show_isis_mpls_ldp_sync_holddown(struct vty *vty,
struct lyd_node *dnode,
bool show_defaults)
{
vty_out(vty, " mpls ldp-sync holddown %s\n",
yang_dnode_get_string(dnode, NULL));
}
/*
* XPath: /frr-interface:lib/interface/frr-isisd:isis/mpls/ldp-sync
*/
DEFPY(isis_mpls_if_ldp_sync, isis_mpls_if_ldp_sync_cmd,
"[no] isis mpls ldp-sync",
NO_STR "IS-IS routing protocol\n" MPLS_STR MPLS_LDP_SYNC_STR)
{
const struct lyd_node *dnode;
struct interface *ifp;
dnode = yang_dnode_get(vty->candidate_config->dnode,
"%s/frr-isisd:isis", VTY_CURR_XPATH);
if (dnode == NULL) {
vty_out(vty, "ISIS is not enabled on this circuit\n");
return CMD_SUCCESS;
}
ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
if (if_is_loopback(ifp)) {
vty_out(vty, "ldp-sync does not run on loopback interface\n");
return CMD_SUCCESS;
}
if (ifp->vrf_id != VRF_DEFAULT) {
vty_out(vty, "ldp-sync only runs on DEFAULT VRF\n");
return CMD_SUCCESS;
}
nb_cli_enqueue_change(vty, "./frr-isisd:isis/mpls/ldp-sync",
NB_OP_MODIFY, no ? "false" : "true");
return nb_cli_apply_changes(vty, NULL);
}
void cli_show_isis_mpls_if_ldp_sync(struct vty *vty, struct lyd_node *dnode,
bool show_defaults)
{
if (!yang_dnode_get_bool(dnode, NULL))
vty_out(vty, " no");
vty_out(vty, " isis mpls ldp-sync\n");
}
DEFPY(isis_mpls_if_ldp_sync_holddown, isis_mpls_if_ldp_sync_holddown_cmd,
"isis mpls ldp-sync holddown (0-10000)",
"IS-IS routing protocol\n" MPLS_STR MPLS_LDP_SYNC_STR
"Time to wait for LDP-SYNC to occur before restoring interface metric\n"
"Time in seconds\n")
{
const struct lyd_node *dnode;
struct interface *ifp;
dnode = yang_dnode_get(vty->candidate_config->dnode,
"%s/frr-isisd:isis", VTY_CURR_XPATH);
if (dnode == NULL) {
vty_out(vty, "ISIS is not enabled on this circuit\n");
return CMD_SUCCESS;
}
ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
if (if_is_loopback(ifp)) {
vty_out(vty, "ldp-sync does not run on loopback interface\n");
return CMD_SUCCESS;
}
if (ifp->vrf_id != VRF_DEFAULT) {
vty_out(vty, "ldp-sync only runs on DEFAULT VRF\n");
return CMD_SUCCESS;
}
nb_cli_enqueue_change(vty, "./frr-isisd:isis/mpls/holddown",
NB_OP_MODIFY, holddown_str);
return nb_cli_apply_changes(vty, NULL);
}
DEFPY(no_isis_mpls_if_ldp_sync_holddown, no_isis_mpls_if_ldp_sync_holddown_cmd,
"no isis mpls ldp-sync holddown [<(1-10000)>]",
NO_STR "IS-IS routing protocol\n" MPLS_STR NO_MPLS_LDP_SYNC_STR
NO_MPLS_LDP_SYNC_HOLDDOWN_STR)
{
const struct lyd_node *dnode;
struct interface *ifp;
dnode = yang_dnode_get(vty->candidate_config->dnode,
"%s/frr-isisd:isis", VTY_CURR_XPATH);
if (dnode == NULL) {
vty_out(vty, "ISIS is not enabled on this circuit\n");
return CMD_SUCCESS;
}
ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
if (if_is_loopback(ifp)) {
vty_out(vty, "ldp-sync does not run on loopback interface\n");
return CMD_SUCCESS;
}
if (ifp->vrf_id != VRF_DEFAULT) {
vty_out(vty, "ldp-sync only runs on DEFAULT VRF\n");
return CMD_SUCCESS;
}
nb_cli_enqueue_change(vty, "./frr-isisd:isis/mpls/holddown",
NB_OP_DESTROY, NULL);
return nb_cli_apply_changes(vty, NULL);
}
void cli_show_isis_mpls_if_ldp_sync_holddown(struct vty *vty,
struct lyd_node *dnode,
bool show_defaults)
{
vty_out(vty, " isis mpls ldp-sync holddown %s\n",
yang_dnode_get_string(dnode, NULL));
}
void isis_cli_init(void)
{
install_element(CONFIG_NODE, &router_isis_cmd);
@ -2489,6 +2661,14 @@ void isis_cli_init(void)
install_element(INTERFACE_NODE, &no_isis_priority_cmd);
install_element(ISIS_NODE, &log_adj_changes_cmd);
install_element(ISIS_NODE, &isis_mpls_ldp_sync_cmd);
install_element(ISIS_NODE, &no_isis_mpls_ldp_sync_cmd);
install_element(ISIS_NODE, &isis_mpls_ldp_sync_holddown_cmd);
install_element(ISIS_NODE, &no_isis_mpls_ldp_sync_holddown_cmd);
install_element(INTERFACE_NODE, &isis_mpls_if_ldp_sync_cmd);
install_element(INTERFACE_NODE, &isis_mpls_if_ldp_sync_holddown_cmd);
install_element(INTERFACE_NODE, &no_isis_mpls_if_ldp_sync_holddown_cmd);
}
#endif /* ifndef FABRICD */

788
isisd/isis_ldp_sync.c Normal file
View File

@ -0,0 +1,788 @@
/**
* isis_ldp_sync.c: ISIS LDP-IGP Sync handling routines
* Copyright (C) 2020 Volta Networks, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <zebra.h>
#include <string.h>
#include "monotime.h"
#include "memory.h"
#include "thread.h"
#include "prefix.h"
#include "table.h"
#include "vty.h"
#include "command.h"
#include "plist.h"
#include "log.h"
#include "zclient.h"
#include <lib/json.h>
#include "defaults.h"
#include "ldp_sync.h"
#include "isisd/isis_constants.h"
#include "isisd/isis_common.h"
#include "isisd/isis_flags.h"
#include "isisd/isis_circuit.h"
#include "isisd/isis_lsp.h"
#include "isisd/isis_pdu.h"
#include "isisd/isis_network.h"
#include "isisd/isis_misc.h"
#include "isisd/isis_constants.h"
#include "isisd/isis_adjacency.h"
#include "isisd/isis_dr.h"
#include "isisd/isisd.h"
#include "isisd/isis_csm.h"
#include "isisd/isis_events.h"
#include "isisd/isis_te.h"
#include "isisd/isis_mt.h"
#include "isisd/isis_errors.h"
#include "isisd/isis_tx_queue.h"
#include "isisd/isis_nb.h"
#include "isisd/isis_ldp_sync.h"
extern struct zclient *zclient;
/*
* LDP-SYNC msg between IGP and LDP
*/
int isis_ldp_sync_state_update(struct ldp_igp_sync_if_state state)
{
struct interface *ifp;
struct isis_circuit *circuit = NULL;
struct isis_area *area;
struct listnode *node;
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
/* if isis is not enabled or LDP-SYNC is not configured ignore */
if (!isis ||
!CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
return 0;
/* lookup circuit */
ifp = if_lookup_by_index(state.ifindex, VRF_DEFAULT);
if (ifp == NULL)
return 0;
for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
circuit = circuit_lookup_by_ifp(ifp, area->circuit_list);
if (circuit != NULL)
break;
}
/* if isis is not enabled or LDP-SYNC is not configured ignore */
if (circuit == NULL ||
!CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
return 0;
/* received ldp-sync interface state from LDP */
ils_debug("ldp_sync: rcvd %s from LDP if %s",
state.sync_start ? "sync-start" : "sync-complete", ifp->name);
if (state.sync_start)
isis_ldp_sync_if_start(circuit, false);
else
isis_ldp_sync_if_complete(circuit);
return 0;
}
int isis_ldp_sync_announce_update(struct ldp_igp_sync_announce announce)
{
struct isis_area *area;
struct listnode *node;
struct vrf *vrf;
struct interface *ifp;
struct isis_circuit *circuit;
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
/* if isis is not enabled or LDP-SYNC is not configured ignore */
if (!isis ||
!CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
return 0;
if (announce.proto != ZEBRA_ROUTE_LDP)
return 0;
ils_debug("ldp_sync: rcvd announce from LDP");
/* LDP just started up:
* set cost to LSInfinity
* send request to LDP for LDP-SYNC state for each interface
* start hello timer
*/
vrf = vrf_lookup_by_id(VRF_DEFAULT);
FOR_ALL_INTERFACES (vrf, ifp) {
for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
circuit = circuit_lookup_by_ifp(ifp,
area->circuit_list);
if (circuit == NULL)
continue;
isis_ldp_sync_if_start(circuit, true);
}
}
THREAD_TIMER_OFF(isis->ldp_sync_cmd.t_hello);
isis->ldp_sync_cmd.t_hello = NULL;
isis->ldp_sync_cmd.sequence = 0;
isis_ldp_sync_hello_timer_add();
return 0;
}
int isis_ldp_sync_hello_update(struct ldp_igp_sync_hello hello)
{
struct isis_area *area;
struct listnode *node;
struct vrf *vrf;
struct interface *ifp;
struct isis_circuit *circuit;
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
/* if isis is not enabled or LDP-SYNC is not configured ignore */
if (!isis ||
!CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
return 0;
if (hello.proto != ZEBRA_ROUTE_LDP)
return 0;
/* Received Hello from LDP:
* if current sequence number is greater than received hello
* sequence number then assume LDP restarted
* set cost to LSInfinity
* send request to LDP for LDP-SYNC state for each interface
* else all is fine just restart hello timer
*/
if (hello.sequence == 0)
/* rolled over */
isis->ldp_sync_cmd.sequence = 0;
if (isis->ldp_sync_cmd.sequence > hello.sequence) {
zlog_err("ldp_sync: LDP restarted");
vrf = vrf_lookup_by_id(VRF_DEFAULT);
FOR_ALL_INTERFACES (vrf, ifp) {
for (ALL_LIST_ELEMENTS_RO(isis->area_list, node,
area)) {
circuit = circuit_lookup_by_ifp(ifp,
area->circuit_list);
if (circuit == NULL)
continue;
isis_ldp_sync_if_start(circuit, true);
}
}
} else {
THREAD_TIMER_OFF(isis->ldp_sync_cmd.t_hello);
isis_ldp_sync_hello_timer_add();
}
isis->ldp_sync_cmd.sequence = hello.sequence;
return 0;
}
void isis_ldp_sync_state_req_msg(struct isis_circuit *circuit)
{
struct ldp_igp_sync_if_state_req request;
struct interface *ifp = circuit->interface;
ils_debug("ldp_sync: send state request to LDP for %s",
ifp->name);
strlcpy(request.name, ifp->name, sizeof(ifp->name));
request.proto = LDP_IGP_SYNC_IF_STATE_REQUEST;
request.ifindex = ifp->ifindex;
zclient_send_opaque(zclient, LDP_IGP_SYNC_IF_STATE_REQUEST,
(uint8_t *)&request, sizeof(request));
}
/*
* LDP-SYNC general interface routines
*/
void isis_ldp_sync_if_init(struct isis_circuit *circuit, struct isis *isis)
{
struct ldp_sync_info *ldp_sync_info;
struct interface *ifp = circuit->interface;
/* called when ISIS is configured on an interface
* if LDP-IGP Sync is configured globally set state
* and if ptop interface LDP LDP-SYNC is enabled
*/
ils_debug("ldp_sync: init if %s ", ifp->name);
if (circuit->ldp_sync_info == NULL)
circuit->ldp_sync_info = ldp_sync_info_create();
ldp_sync_info = circuit->ldp_sync_info;
/* specifed on interface overrides global config. */
if (!CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN))
ldp_sync_info->holddown = isis->ldp_sync_cmd.holddown;
if (!CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG))
ldp_sync_info->enabled = LDP_IGP_SYNC_ENABLED;
if ((circuit->circ_type == CIRCUIT_T_P2P || if_is_pointopoint(ifp)) &&
ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED)
ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
}
void isis_ldp_sync_if_start(struct isis_circuit *circuit,
bool send_state_req)
{
struct ldp_sync_info *ldp_sync_info;
ldp_sync_info = circuit->ldp_sync_info;
/* Start LDP-SYNC on this interface:
* set cost of interface to LSInfinity so traffic will use different
* interface until LDP has learned all labels from peer
* start holddown timer if configured
* send msg to LDP to get LDP-SYNC state
*/
if (ldp_sync_info &&
ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED &&
ldp_sync_info->state != LDP_IGP_SYNC_STATE_NOT_REQUIRED) {
ils_debug("ldp_sync: start on if %s state: %s",
circuit->interface->name, "Holding down until Sync");
ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
isis_ldp_sync_set_if_metric(circuit, true);
isis_ldp_sync_holddown_timer_add(circuit);
if (send_state_req)
isis_ldp_sync_state_req_msg(circuit);
}
}
void isis_ldp_sync_if_complete(struct isis_circuit *circuit)
{
struct ldp_sync_info *ldp_sync_info;
ldp_sync_info = circuit->ldp_sync_info;
/* received sync-complete from LDP:
* set state to up
* stop timer
* restore interface cost to original value
*/
if (ldp_sync_info && ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED) {
if (ldp_sync_info->state == LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP)
ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_UP;
THREAD_TIMER_OFF(ldp_sync_info->t_holddown);
ldp_sync_info->t_holddown = NULL;
isis_ldp_sync_set_if_metric(circuit, true);
}
}
void isis_ldp_sync_ldp_fail(struct isis_circuit *circuit)
{
struct ldp_sync_info *ldp_sync_info;
ldp_sync_info = circuit->ldp_sync_info;
/* LDP failed to send hello:
* stop holddown timer
* set cost of interface to LSInfinity so traffic will use different
* interface until LDP restarts and has learned all labels from peer
*/
if (ldp_sync_info &&
ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED &&
ldp_sync_info->state != LDP_IGP_SYNC_STATE_NOT_REQUIRED) {
if (ldp_sync_info->t_holddown != NULL) {
THREAD_TIMER_OFF(ldp_sync_info->t_holddown);
ldp_sync_info->t_holddown = NULL;
}
ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
isis_ldp_sync_set_if_metric(circuit, true);
}
}
void isis_ldp_sync_if_remove(struct isis_circuit *circuit, bool remove)
{
struct ldp_sync_info *ldp_sync_info;
if (circuit->ldp_sync_info == NULL)
return;
ldp_sync_info = circuit->ldp_sync_info;
/* Stop LDP-SYNC on this interface:
* if holddown timer is running stop it
* delete ldp instance on interface
* restore metric
*/
ils_debug("ldp_sync: remove if %s", circuit->interface
? circuit->interface->name : "");
if (ldp_sync_info->t_holddown)
THREAD_TIMER_OFF(ldp_sync_info->t_holddown);
ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED;
isis_ldp_sync_set_if_metric(circuit, true);
if (remove) {
/* ISIS instance being removed free ldp-sync info */
ldp_sync_info_free((struct ldp_sync_info **)&(ldp_sync_info));
circuit->ldp_sync_info = NULL;
}
}
static int isis_ldp_sync_adj_state_change(struct isis_adjacency *adj)
{
struct isis_circuit *circuit = adj->circuit;
struct ldp_sync_info *ldp_sync_info;
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
if (!isis ||
!CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE) ||
circuit->interface->vrf_id != VRF_DEFAULT ||
if_is_loopback(circuit->interface))
return 0;
if (circuit->ldp_sync_info == NULL)
isis_ldp_sync_if_init(circuit, isis);
ldp_sync_info = circuit->ldp_sync_info;
if (ldp_sync_info->enabled != LDP_IGP_SYNC_ENABLED)
return 0;
if (adj->adj_state == ISIS_ADJ_UP) {
if (circuit->circ_type == CIRCUIT_T_P2P ||
if_is_pointopoint(circuit->interface)) {
/* If LDP-SYNC is configure on interface then start */
ldp_sync_info->state =
LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
isis_ldp_sync_if_start(circuit, true);
} else {
/* non ptop link so don't run ldp-sync */
ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED;
isis_ldp_sync_set_if_metric(circuit, true);
}
} else {
/* If LDP-SYNC is configure on this interface then stop it */
if (circuit->circ_type == CIRCUIT_T_P2P ||
if_is_pointopoint(circuit->interface))
ldp_sync_info->state =
LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
else
ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED;
ils_debug("ldp_sync: down on if %s", circuit->interface->name);
ldp_sync_if_down(circuit->ldp_sync_info);
}
return 0;
}
bool isis_ldp_sync_if_metric_config(struct isis_circuit *circuit, int level,
int metric)
{
struct ldp_sync_info *ldp_sync_info = circuit->ldp_sync_info;
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
/* configured interface metric has been changed:
* if LDP-IGP Sync is running and metric has been set to LSInfinity
* change saved value so when ldp-sync completes proper metric is
* restored
*/
if (isis &&
CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE) &&
ldp_sync_info != NULL) {
if (CHECK_FLAG(ldp_sync_info->flags,
LDP_SYNC_FLAG_SET_METRIC)) {
ldp_sync_info->metric[level-1] = metric;
ldp_sync_info->metric[level-1] = metric;
return false;
}
}
return true;
}
void isis_ldp_sync_set_if_metric(struct isis_circuit *circuit, bool run_regen)
{
struct ldp_sync_info *ldp_sync_info;
/* set interface metric:
* if LDP-IGP Sync is starting set metric so interface
* is used only as last resort
* else restore metric to original value
*/
if (circuit->ldp_sync_info == NULL || circuit->area == NULL)
return;
ldp_sync_info = circuit->ldp_sync_info;
if (ldp_sync_if_is_enabled(ldp_sync_info)) {
/* if metric already set to LSInfinity just return */
if (CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_SET_METRIC))
return;
SET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_SET_METRIC);
if (circuit->is_type & IS_LEVEL_1) {
if (circuit->area->newmetric) {
ldp_sync_info->metric[0] =
circuit->te_metric[0];
circuit->te_metric[0] = LDP_ISIS_LSINFINITY;
} else {
ldp_sync_info->metric[0] = circuit->metric[0];
circuit->metric[0] = LDP_ISIS_LSINFINITY_NL;
}
}
if (circuit->is_type & IS_LEVEL_2) {
if (circuit->area->newmetric) {
ldp_sync_info->metric[1] =
circuit->te_metric[1];
circuit->te_metric[1] = LDP_ISIS_LSINFINITY;
} else {
ldp_sync_info->metric[1] = circuit->metric[1];
circuit->metric[1] = LDP_ISIS_LSINFINITY_NL;
}
}
} else {
/* if metric already restored just return */
if (!CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_SET_METRIC))
return;
UNSET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_SET_METRIC);
if (circuit->is_type & IS_LEVEL_1) {
circuit->te_metric[0] = ldp_sync_info->metric[0];
circuit->metric[0] = ldp_sync_info->metric[0];
}
if (circuit->is_type & IS_LEVEL_2) {
circuit->te_metric[1] = ldp_sync_info->metric[1];
circuit->metric[1] = ldp_sync_info->metric[1];
}
}
if (run_regen)
lsp_regenerate_schedule(circuit->area, circuit->is_type, 0);
}
/*
* LDP-SYNC holddown timer routines
*/
static int isis_ldp_sync_holddown_timer(struct thread *thread)
{
struct isis_circuit *circuit;
struct ldp_sync_info *ldp_sync_info;
/* holddown timer expired:
* didn't receive msg from LDP indicating sync-complete
* restore interface cost to original value
*/
circuit = THREAD_ARG(thread);
if (circuit->ldp_sync_info == NULL)
return 0;
ldp_sync_info = circuit->ldp_sync_info;
ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_UP;
ldp_sync_info->t_holddown = NULL;
ils_debug("ldp_sync: holddown timer expired for %s state:sync achieved",
circuit->interface->name);
isis_ldp_sync_set_if_metric(circuit, true);
return 0;
}
void isis_ldp_sync_holddown_timer_add(struct isis_circuit *circuit)
{
struct ldp_sync_info *ldp_sync_info;
ldp_sync_info = circuit->ldp_sync_info;
/* Start holddown timer:
* this timer is used to keep interface cost at LSInfinity
* once expires returns cost to original value
* if timer is already running or holddown time is off just return
*/
if (ldp_sync_info->t_holddown ||
ldp_sync_info->holddown == LDP_IGP_SYNC_HOLDDOWN_DEFAULT)
return;
ils_debug("ldp_sync: start holddown timer for %s time %d",
circuit->interface->name, ldp_sync_info->holddown);
thread_add_timer(master, isis_ldp_sync_holddown_timer,
circuit, ldp_sync_info->holddown,
&ldp_sync_info->t_holddown);
}
/*
* LDP-SYNC hello timer routines
*/
static int isis_ldp_sync_hello_timer(struct thread *thread)
{
struct isis_area *area;
struct listnode *node;
struct isis_circuit *circuit;
struct interface *ifp;
struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
if (!isis)
return 0;
/* hello timer expired:
* didn't receive hello msg from LDP
* set cost of all interfaces to LSInfinity
*/
FOR_ALL_INTERFACES (vrf, ifp) {
for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
circuit = circuit_lookup_by_ifp(ifp,
area->circuit_list);
if (circuit == NULL)
continue;
isis_ldp_sync_ldp_fail(circuit);
}
}
zlog_debug("ldp_sync: hello timer expired, LDP down");
return 0;
}
void isis_ldp_sync_hello_timer_add(void)
{
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
/* Start hello timer:
* this timer is used to make sure LDP is up
* if expires set interface cost to LSInfinity
*/
if (!isis ||
!CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
return;
thread_add_timer(master, isis_ldp_sync_hello_timer,
NULL, LDP_IGP_SYNC_HELLO_TIMEOUT,
&isis->ldp_sync_cmd.t_hello);
}
/*
* LDP-SYNC routes used by set commands.
*/
void isis_if_set_ldp_sync_enable(struct isis_circuit *circuit)
{
struct ldp_sync_info *ldp_sync_info;
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
/* called when setting LDP-SYNC at the global level:
* specifed on interface overrides global config
* if ptop link send msg to LDP indicating ldp-sync enabled
*/
if (!isis || if_is_loopback(circuit->interface))
return;
if (CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) {
if (circuit->ldp_sync_info == NULL)
isis_ldp_sync_if_init(circuit, isis);
ldp_sync_info = circuit->ldp_sync_info;
/* config on interface, overrides global config. */
if (CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG))
if (ldp_sync_info->enabled != LDP_IGP_SYNC_ENABLED)
return;
ldp_sync_info->enabled = LDP_IGP_SYNC_ENABLED;
ils_debug("ldp_sync: enable if %s", circuit->interface->name);
/* send message to LDP if ptop link */
if (circuit->circ_type == CIRCUIT_T_P2P ||
if_is_pointopoint(circuit->interface)) {
ldp_sync_info->state =
LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
isis_ldp_sync_state_req_msg(circuit);
} else {
ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED;
zlog_debug("ldp_sync: Sync only runs on P2P links %s",
circuit->interface->name);
}
} else
/* delete LDP sync even if configured on an interface */
isis_ldp_sync_if_remove(circuit, false);
}
void isis_if_set_ldp_sync_holddown(struct isis_circuit *circuit)
{
struct ldp_sync_info *ldp_sync_info;
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
/* called when setting LDP-SYNC at the global level:
* specifed on interface overrides global config.
*/
if (!isis || if_is_loopback(circuit->interface))
return;
if (circuit->ldp_sync_info == NULL)
isis_ldp_sync_if_init(circuit, isis);
ldp_sync_info = circuit->ldp_sync_info;
/* config on interface, overrides global config. */
if (CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN))
return;
if (CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN))
ldp_sync_info->holddown = isis->ldp_sync_cmd.holddown;
else
ldp_sync_info->holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT;
}
void isis_ldp_sync_gbl_exit(bool remove)
{
struct isis_area *area;
struct listnode *node;
struct isis_circuit *circuit;
struct interface *ifp;
struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
/* if you delete LDP-SYNC at a gobal level is clears all LDP-SYNC
* configuration, even interface configuration
*/
if (isis &&
CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) {
/* register with opaque client to recv LDP-IGP Sync msgs */
zclient_unregister_opaque(zclient,
LDP_IGP_SYNC_IF_STATE_UPDATE);
zclient_unregister_opaque(zclient,
LDP_IGP_SYNC_ANNOUNCE_UPDATE);
zclient_unregister_opaque(zclient, LDP_IGP_SYNC_HELLO_UPDATE);
/* disable LDP-SYNC globally */
UNSET_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE);
UNSET_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN);
isis->ldp_sync_cmd.holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT;
THREAD_TIMER_OFF(isis->ldp_sync_cmd.t_hello);
isis->ldp_sync_cmd.t_hello = NULL;
/* remove LDP-SYNC on all ISIS interfaces */
FOR_ALL_INTERFACES (vrf, ifp) {
for (ALL_LIST_ELEMENTS_RO(isis->area_list, node,
area)) {
circuit = circuit_lookup_by_ifp(ifp,
area->circuit_list);
if (circuit == NULL)
continue;
isis_ldp_sync_if_remove(circuit, remove);
}
}
}
}
/*
* LDP-SYNC routines used by show commands.
*/
static void isis_circuit_ldp_sync_print_vty(struct isis_circuit *circuit,
struct vty *vty)
{
struct ldp_sync_info *ldp_sync_info;
const char *ldp_state;
if (circuit->ldp_sync_info == NULL ||
if_is_loopback(circuit->interface))
return;
ldp_sync_info = circuit->ldp_sync_info;
vty_out(vty, "%-10s\n", circuit->interface->name);
vty_out(vty, " LDP-IGP Synchronization enabled: %s\n",
ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED
? "yes"
: "no");
vty_out(vty, " holddown timer in seconds: %u\n",
ldp_sync_info->holddown);
switch (ldp_sync_info->state) {
case LDP_IGP_SYNC_STATE_REQUIRED_UP:
vty_out(vty, " State: Sync achieved\n");
break;
case LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP:
if (ldp_sync_info->t_holddown != NULL) {
struct timeval remain = thread_timer_remain(
ldp_sync_info->t_holddown);
vty_out(vty,
" Holddown timer is running %lld.%03lld remaining\n",
(long long)remain.tv_sec,
(long long)remain.tv_usec/1000);
vty_out(vty, " State: Holding down until Sync\n");
} else
vty_out(vty, " State: Sync not achieved\n");
break;
case LDP_IGP_SYNC_STATE_NOT_REQUIRED:
default:
if ((circuit->circ_type != CIRCUIT_T_P2P &&
!if_is_pointopoint(circuit->interface)) &&
circuit->circ_type != CIRCUIT_T_UNKNOWN)
ldp_state = "Sync not required: non-p2p link";
else
ldp_state = "Sync not required";
vty_out(vty, " State: %s\n", ldp_state);
break;
}
}
DEFUN (show_isis_mpls_ldp_interface,
show_isis_mpls_ldp_interface_cmd,
"show " PROTO_NAME " mpls ldp-sync [interface <INTERFACE|all>]",
SHOW_STR
PROTO_HELP
MPLS_STR
"LDP-IGP Sync information\n"
"Interface name\n")
{
char *ifname = NULL;
int idx_intf = 0;
struct listnode *anode, *cnode;
struct isis_area *area;
struct isis_circuit *circuit;
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
if (!isis) {
vty_out(vty, "IS-IS Routing Process not enabled\n");
return CMD_SUCCESS;
}
if (!CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) {
vty_out(vty, "LDP-sync is disabled\n");
return CMD_SUCCESS;
}
if (argv_find(argv, argc, "INTERFACE", &idx_intf))
ifname = argv[idx_intf]->arg;
for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) {
for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit))
if (!ifname)
isis_circuit_ldp_sync_print_vty(circuit, vty);
else if (strcmp(circuit->interface->name, ifname) == 0)
isis_circuit_ldp_sync_print_vty(circuit, vty);
}
return CMD_SUCCESS;
}
void isis_ldp_sync_init(void)
{
/* "show ip isis mpls ldp interface" commands. */
install_element(VIEW_NODE, &show_isis_mpls_ldp_interface_cmd);
/* register for adjacency state changes */
hook_register(isis_adj_state_change_hook,
isis_ldp_sync_adj_state_change);
}

54
isisd/isis_ldp_sync.h Normal file
View File

@ -0,0 +1,54 @@
/*
* isis_ldp_sync.h: ISIS LDP-IGP Sync handling routines
* Copyright (C) 2020 Volta Networks, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _ZEBRA_ISIS_LDP_SYNC_H
#define _ZEBRA_ISIS_LDP_SYNC_H
#define LDP_ISIS_LSINFINITY 0xFFFFFE /* wide link metric */
#define LDP_ISIS_LSINFINITY_NL 62 /* narrow link metric */
/* Macro to log debug message */
#define ils_debug(...) \
do { \
if (IS_DEBUG_LDP_SYNC) \
zlog_debug(__VA_ARGS__); \
} while (0)
extern void isis_if_set_ldp_sync_enable(struct isis_circuit *circuit);
extern void isis_if_set_ldp_sync_holddown(struct isis_circuit *circuit);
extern void isis_ldp_sync_if_init(struct isis_circuit *circuit,
struct isis *isis);
extern void isis_ldp_sync_if_start(struct isis_circuit *circuit,
bool send_state_req);
extern void isis_ldp_sync_if_remove(struct isis_circuit *circuit, bool remove);
extern void isis_ldp_sync_if_complete(struct isis_circuit *circuit);
extern void isis_ldp_sync_holddown_timer_add(struct isis_circuit *circuit);
extern void isis_ldp_sync_hello_timer_add(void);
extern void isis_ldp_sync_ldp_fail(struct isis_circuit *circuit);
extern int isis_ldp_sync_state_update(struct ldp_igp_sync_if_state state);
extern int isis_ldp_sync_announce_update(struct ldp_igp_sync_announce announce);
extern int isis_ldp_sync_hello_update(struct ldp_igp_sync_hello hello);
extern void isis_ldp_sync_state_req_msg(struct isis_circuit *circuit);
extern void isis_ldp_sync_set_if_metric(struct isis_circuit *circuit,
bool run_regen);
extern bool isis_ldp_sync_if_metric_config(struct isis_circuit *circuit,
int level, int metric);
extern void isis_ldp_sync_init(void);
extern void isis_ldp_sync_gbl_exit(bool remove);
#endif /* _ZEBRA_ISIS_LDP_SYNC_H */

View File

@ -58,6 +58,7 @@
#include "isisd/isis_mt.h"
#include "isisd/fabricd.h"
#include "isisd/isis_nb.h"
#include "isisd/isis_ldp_sync.h"
/* Default configuration file name */
#define ISISD_DEFAULT_CONFIG "isisd.conf"
@ -264,6 +265,7 @@ int main(int argc, char **argv, char **envp)
isis_zebra_init(master, instance);
isis_bfd_init();
isis_ldp_sync_init();
fabricd_init();
frr_config_fork();

View File

@ -537,6 +537,21 @@ const struct frr_yang_module_info frr_isisd_info = {
.modify = isis_instance_segment_routing_prefix_sid_map_prefix_sid_last_hop_behavior_modify,
},
},
{
.xpath = "/frr-isisd:isis/instance/mpls/ldp-sync",
.cbs = {
.cli_show = cli_show_isis_mpls_ldp_sync,
.create = isis_instance_mpls_ldp_sync_create,
.destroy = isis_instance_mpls_ldp_sync_destroy,
},
},
{
.xpath = "/frr-isisd:isis/instance/mpls/ldp-sync/holddown",
.cbs = {
.cli_show = cli_show_isis_mpls_ldp_sync_holddown,
.modify = isis_instance_mpls_ldp_sync_holddown_modify,
},
},
{
.xpath = "/frr-interface:lib/interface/frr-isisd:isis",
.cbs = {
@ -905,6 +920,21 @@ const struct frr_yang_module_info frr_isisd_info = {
.get_elem = lib_interface_state_isis_event_counters_authentication_fails_get_elem,
}
},
{
.xpath = "/frr-interface:lib/interface/frr-isisd:isis/mpls/ldp-sync",
.cbs = {
.cli_show = cli_show_isis_mpls_if_ldp_sync,
.modify = lib_interface_isis_mpls_ldp_sync_modify,
}
},
{
.xpath = "/frr-interface:lib/interface/frr-isisd:isis/mpls/holddown",
.cbs = {
.cli_show = cli_show_isis_mpls_if_ldp_sync_holddown,
.modify = lib_interface_isis_mpls_holddown_modify,
.destroy = lib_interface_isis_mpls_holddown_destroy,
}
},
{
.xpath = NULL,
},

View File

@ -206,6 +206,9 @@ int isis_instance_segment_routing_prefix_sid_map_prefix_sid_sid_value_modify(
struct nb_cb_modify_args *args);
int isis_instance_segment_routing_prefix_sid_map_prefix_sid_last_hop_behavior_modify(
struct nb_cb_modify_args *args);
int isis_instance_mpls_ldp_sync_destroy(struct nb_cb_destroy_args *args);
int isis_instance_mpls_ldp_sync_create(struct nb_cb_create_args *args);
int isis_instance_mpls_ldp_sync_holddown_modify(struct nb_cb_modify_args *args);
int lib_interface_isis_csnp_interval_level_1_modify(
struct nb_cb_modify_args *args);
int lib_interface_isis_csnp_interval_level_2_modify(
@ -250,6 +253,9 @@ int lib_interface_isis_multi_topology_ipv6_management_modify(
struct nb_cb_modify_args *args);
int lib_interface_isis_multi_topology_ipv6_dstsrc_modify(
struct nb_cb_modify_args *args);
int lib_interface_isis_mpls_ldp_sync_modify(struct nb_cb_modify_args *args);
int lib_interface_isis_mpls_holddown_modify(struct nb_cb_modify_args *args);
int lib_interface_isis_mpls_holddown_destroy(struct nb_cb_destroy_args *args);
struct yang_data *
lib_interface_state_isis_get_elem(struct nb_cb_get_elem_args *args);
const void *lib_interface_state_isis_adjacencies_adjacency_get_next(
@ -434,6 +440,16 @@ void cli_show_ip_isis_priority(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
void cli_show_isis_log_adjacency(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
void cli_show_isis_mpls_ldp_sync(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
void cli_show_isis_mpls_ldp_sync_holddown(struct vty *vty,
struct lyd_node *dnode,
bool show_defaults);
void cli_show_isis_mpls_if_ldp_sync(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
void cli_show_isis_mpls_if_ldp_sync_holddown(struct vty *vty,
struct lyd_node *dnode,
bool show_defaults);
/* Notifications. */
void isis_notif_db_overload(const struct isis_area *area, bool overload);

View File

@ -29,6 +29,8 @@
#include "spf_backoff.h"
#include "lib_errors.h"
#include "vrf.h"
#include "zclient.h"
#include "ldp_sync.h"
#include "isisd/isisd.h"
#include "isisd/isis_nb.h"
@ -45,6 +47,9 @@
#include "isisd/isis_memory.h"
#include "isisd/isis_mt.h"
#include "isisd/isis_redist.h"
#include "isisd/isis_ldp_sync.h"
extern struct zclient *zclient;
/*
* XPath: /frr-isisd:isis/instance
@ -81,6 +86,10 @@ int isis_instance_destroy(struct nb_cb_destroy_args *args)
area = nb_running_unset_entry(args->dnode);
isis_area_destroy(area);
/* remove ldp-sync config */
if (area->isis->vrf_id == VRF_DEFAULT)
isis_ldp_sync_gbl_exit(true);
return NB_OK;
}
@ -1825,6 +1834,113 @@ int isis_instance_segment_routing_prefix_sid_map_prefix_sid_last_hop_behavior_mo
return NB_OK;
}
/*
* XPath: /frr-isisd:isis/instance/mpls/ldp-sync
*/
int isis_instance_mpls_ldp_sync_create(struct nb_cb_create_args *args)
{
struct isis_area *area;
struct listnode *node;
struct isis_circuit *circuit;
struct interface *ifp;
struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
switch (args->event) {
case NB_EV_VALIDATE:
if (isis == NULL)
return NB_ERR_VALIDATION;
break;
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
/* register with opaque client to recv LDP-IGP Sync msgs */
zclient_register_opaque(zclient, LDP_IGP_SYNC_IF_STATE_UPDATE);
zclient_register_opaque(zclient, LDP_IGP_SYNC_ANNOUNCE_UPDATE);
zclient_register_opaque(zclient, LDP_IGP_SYNC_HELLO_UPDATE);
if (!CHECK_FLAG(isis->ldp_sync_cmd.flags,
LDP_SYNC_FLAG_ENABLE)) {
SET_FLAG(isis->ldp_sync_cmd.flags,
LDP_SYNC_FLAG_ENABLE);
/* turn on LDP-IGP Sync on all ptop ISIS interfaces */
FOR_ALL_INTERFACES (vrf, ifp) {
for (ALL_LIST_ELEMENTS_RO(isis->area_list, node,
area)) {
circuit = circuit_lookup_by_ifp(
ifp, area->circuit_list);
if (circuit == NULL)
continue;
isis_if_set_ldp_sync_enable(circuit);
}
}
}
break;
}
return NB_OK;
}
int isis_instance_mpls_ldp_sync_destroy(struct nb_cb_destroy_args *args)
{
if (args->event != NB_EV_APPLY)
return NB_OK;
/* remove ldp-sync config */
isis_ldp_sync_gbl_exit(false);
return NB_OK;
}
/*
* XPath: /frr-isisd:isis/instance/mpls/ldp-sync/holddown
*/
int isis_instance_mpls_ldp_sync_holddown_modify(struct nb_cb_modify_args *args)
{
struct isis_area *area;
struct listnode *node;
struct isis_circuit *circuit;
struct interface *ifp;
struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
uint16_t holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT;
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
switch (args->event) {
case NB_EV_VALIDATE:
if (isis == NULL)
return NB_ERR_VALIDATION;
break;
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
holddown = yang_dnode_get_uint16(args->dnode, NULL);
if (holddown == LDP_IGP_SYNC_HOLDDOWN_DEFAULT)
UNSET_FLAG(isis->ldp_sync_cmd.flags,
LDP_SYNC_FLAG_HOLDDOWN);
else
SET_FLAG(isis->ldp_sync_cmd.flags,
LDP_SYNC_FLAG_HOLDDOWN);
isis->ldp_sync_cmd.holddown = holddown;
/* set holddown time on all ISIS interfaces */
FOR_ALL_INTERFACES (vrf, ifp) {
for (ALL_LIST_ELEMENTS_RO(isis->area_list, node,
area)) {
circuit = circuit_lookup_by_ifp(ifp,
area->circuit_list);
if (circuit == NULL)
continue;
isis_if_set_ldp_sync_holddown(circuit);
}
}
break;
}
return NB_OK;
}
/*
* XPath: /frr-interface:lib/interface/frr-isisd:isis
*/
@ -1915,6 +2031,9 @@ int lib_interface_isis_destroy(struct nb_cb_destroy_args *args)
if (!circuit)
return NB_ERR_INCONSISTENCY;
/* remove ldp-sync config */
isis_ldp_sync_if_remove(circuit, true);
/* disable both AFs for this circuit. this will also update the
* CSM state by sending an ISIS_DISABLED signal. If there is no
* area associated to the circuit there is nothing to do
@ -2646,3 +2765,130 @@ int lib_interface_isis_multi_topology_ipv6_dstsrc_modify(
args->event, args->dnode, args->errmsg, args->errmsg_len,
ISIS_MT_IPV6_DSTSRC);
}
/*
* XPath: /frr-interface:lib/interface/frr-isisd:isis/mpls/ldp-sync
*/
int lib_interface_isis_mpls_ldp_sync_modify(struct nb_cb_modify_args *args)
{
struct isis_circuit *circuit;
struct ldp_sync_info *ldp_sync_info;
bool ldp_sync_enable;
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
switch (args->event) {
case NB_EV_VALIDATE:
if (isis == NULL)
return NB_ERR_VALIDATION;
break;
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
circuit = nb_running_get_entry(args->dnode, NULL, true);
ldp_sync_enable = yang_dnode_get_bool(args->dnode, NULL);
if (circuit->ldp_sync_info == NULL)
isis_ldp_sync_if_init(circuit, isis);
ldp_sync_info = circuit->ldp_sync_info;
if (ldp_sync_enable) {
/* enable LDP-SYNC on an interface
* if ptop interface send message to LDP to get state
*/
SET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG);
ldp_sync_info->enabled = LDP_IGP_SYNC_ENABLED;
if (circuit->circ_type == CIRCUIT_T_P2P) {
ldp_sync_info->state =
LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
isis_ldp_sync_state_req_msg(circuit);
} else {
zlog_debug("ldp_sync: only runs on P2P links %s",
circuit->interface->name);
ldp_sync_info->state =
LDP_IGP_SYNC_STATE_NOT_REQUIRED;
}
} else {
/* disable LDP-SYNC on an interface
* stop holddown timer if running
* restore isis metric
*/
SET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG);
ldp_sync_info->enabled = LDP_IGP_SYNC_DEFAULT;
ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED;
THREAD_TIMER_OFF(ldp_sync_info->t_holddown);
ldp_sync_info->t_holddown = NULL;
isis_ldp_sync_set_if_metric(circuit, true);
}
break;
}
return NB_OK;
}
/*
* XPath: /frr-interface:lib/interface/frr-isisd:isis/mpls/holddown
*/
int lib_interface_isis_mpls_holddown_modify(struct nb_cb_modify_args *args)
{
struct isis_circuit *circuit;
struct ldp_sync_info *ldp_sync_info;
uint16_t holddown;
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
switch (args->event) {
case NB_EV_VALIDATE:
if (isis == NULL)
return NB_ERR_VALIDATION;
break;
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
circuit = nb_running_get_entry(args->dnode, NULL, true);
holddown = yang_dnode_get_uint16(args->dnode, NULL);
if (circuit->ldp_sync_info == NULL)
isis_ldp_sync_if_init(circuit, isis);
ldp_sync_info = circuit->ldp_sync_info;
SET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN);
ldp_sync_info->holddown = holddown;
break;
}
return NB_OK;
}
int lib_interface_isis_mpls_holddown_destroy(struct nb_cb_destroy_args *args)
{
struct isis_circuit *circuit;
struct ldp_sync_info *ldp_sync_info;
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
switch (args->event) {
case NB_EV_VALIDATE:
if (isis == NULL)
return NB_ERR_VALIDATION;
circuit = nb_running_get_entry(args->dnode, NULL, true);
if (circuit->ldp_sync_info == NULL)
return NB_ERR_VALIDATION;
break;
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
circuit = nb_running_get_entry(args->dnode, NULL, true);
ldp_sync_info = circuit->ldp_sync_info;
UNSET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN);
if (CHECK_FLAG(isis->ldp_sync_cmd.flags,
LDP_SYNC_FLAG_HOLDDOWN))
ldp_sync_info->holddown = isis->ldp_sync_cmd.holddown;
else
ldp_sync_info->holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT;
break;
}
return NB_OK;
}

View File

@ -52,6 +52,7 @@
#include "isisd/isis_adjacency.h"
#include "isisd/isis_te.h"
#include "isisd/isis_sr.h"
#include "isisd/isis_ldp_sync.h"
struct zclient *zclient;
static struct zclient *zclient_sync;
@ -596,6 +597,44 @@ static void isis_zebra_connected(struct zclient *zclient)
zclient_send_reg_requests(zclient, VRF_DEFAULT);
}
/*
* opaque messages between processes
*/
static int isis_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
{
struct stream *s;
struct zapi_opaque_msg info;
struct ldp_igp_sync_if_state state;
struct ldp_igp_sync_announce announce;
struct ldp_igp_sync_hello hello;
int ret = 0;
s = zclient->ibuf;
if (zclient_opaque_decode(s, &info) != 0)
return -1;
switch (info.type) {
case LDP_IGP_SYNC_IF_STATE_UPDATE:
STREAM_GET(&state, s, sizeof(state));
ret = isis_ldp_sync_state_update(state);
break;
case LDP_IGP_SYNC_ANNOUNCE_UPDATE:
STREAM_GET(&announce, s, sizeof(announce));
ret = isis_ldp_sync_announce_update(announce);
break;
case LDP_IGP_SYNC_HELLO_UPDATE:
STREAM_GET(&hello, s, sizeof(hello));
ret = isis_ldp_sync_hello_update(hello);
break;
default:
break;
}
stream_failure:
return ret;
}
void isis_zebra_init(struct thread_master *master, int instance)
{
/* Initialize asynchronous zclient. */
@ -622,6 +661,8 @@ void isis_zebra_init(struct thread_master *master, int instance)
*/
zclient_sync->session_id = 1;
zclient_sync->privs = &isisd_privs;
zclient->opaque_msg_handler = isis_opaque_msg_handler;
}
void isis_zebra_stop(void)

View File

@ -76,6 +76,7 @@ unsigned long debug_flooding;
unsigned long debug_bfd;
unsigned long debug_tx_queue;
unsigned long debug_sr;
unsigned long debug_ldp_sync;
DEFINE_QOBJ_TYPE(isis_area)
@ -1207,6 +1208,8 @@ void print_debug(struct vty *vty, int flags, int onoff)
vty_out(vty, "IS-IS Flooding debugging is %s\n", onoffs);
if (flags & DEBUG_BFD)
vty_out(vty, "IS-IS BFD debugging is %s\n", onoffs);
if (flags & DEBUG_LDP_SYNC)
vty_out(vty, "IS-IS ldp-sync debugging is %s\n", onoffs);
}
DEFUN_NOSH (show_debugging,
@ -1244,6 +1247,8 @@ DEFUN_NOSH (show_debugging,
print_debug(vty, DEBUG_FLOODING, 1);
if (IS_DEBUG_BFD)
print_debug(vty, DEBUG_BFD, 1);
if (IS_DEBUG_LDP_SYNC)
print_debug(vty, DEBUG_LDP_SYNC, 1);
return CMD_SUCCESS;
}
@ -1312,6 +1317,10 @@ static int config_write_debug(struct vty *vty)
vty_out(vty, "debug " PROTO_NAME " bfd\n");
write++;
}
if (IS_DEBUG_LDP_SYNC) {
vty_out(vty, "debug " PROTO_NAME " ldp-sync\n");
write++;
}
write += spf_backoff_write_config(vty);
return write;
@ -1668,11 +1677,32 @@ DEFUN (no_debug_isis_bfd,
return CMD_SUCCESS;
}
DEFUN(show_hostname, show_hostname_cmd,
"show " PROTO_NAME " [vrf <NAME|all>] hostname",
SHOW_STR PROTO_HELP VRF_CMD_HELP_STR
"All VRFs\n"
"IS-IS Dynamic hostname mapping\n")
DEFUN(debug_isis_ldp_sync, debug_isis_ldp_sync_cmd,
"debug " PROTO_NAME " ldp-sync",
DEBUG_STR PROTO_HELP PROTO_NAME " interaction with LDP-Sync\n")
{
debug_ldp_sync |= DEBUG_LDP_SYNC;
print_debug(vty, DEBUG_LDP_SYNC, 1);
return CMD_SUCCESS;
}
DEFUN(no_debug_isis_ldp_sync, no_debug_isis_ldp_sync_cmd,
"no debug " PROTO_NAME " ldp-sync",
NO_STR UNDEBUG_STR PROTO_HELP PROTO_NAME " interaction with LDP-Sync\n")
{
debug_ldp_sync &= ~DEBUG_LDP_SYNC;
print_debug(vty, DEBUG_LDP_SYNC, 0);
return CMD_SUCCESS;
}
DEFUN (show_hostname,
show_hostname_cmd,
"show " PROTO_NAME " hostname",
SHOW_STR
PROTO_HELP
"IS-IS Dynamic hostname mapping\n")
{
struct listnode *node;
const char *vrf_name = VRF_DEFAULT_NAME;
@ -2830,6 +2860,8 @@ void isis_init(void)
install_element(ENABLE_NODE, &no_debug_isis_lsp_sched_cmd);
install_element(ENABLE_NODE, &debug_isis_bfd_cmd);
install_element(ENABLE_NODE, &no_debug_isis_bfd_cmd);
install_element(ENABLE_NODE, &debug_isis_ldp_sync_cmd);
install_element(ENABLE_NODE, &no_debug_isis_ldp_sync_cmd);
install_element(CONFIG_NODE, &debug_isis_adj_cmd);
install_element(CONFIG_NODE, &no_debug_isis_adj_cmd);
@ -2857,6 +2889,8 @@ void isis_init(void)
install_element(CONFIG_NODE, &no_debug_isis_lsp_sched_cmd);
install_element(CONFIG_NODE, &debug_isis_bfd_cmd);
install_element(CONFIG_NODE, &no_debug_isis_bfd_cmd);
install_element(CONFIG_NODE, &debug_isis_ldp_sync_cmd);
install_element(CONFIG_NODE, &no_debug_isis_ldp_sync_cmd);
install_default(ROUTER_NODE);

View File

@ -35,6 +35,7 @@
#include "isis_lsp.h"
#include "isis_memory.h"
#include "qobj.h"
#include "ldp_sync.h"
#ifdef FABRICD
static const bool fabricd = true;
@ -93,6 +94,7 @@ struct isis {
uint32_t circuit_ids_used[8]; /* 256 bits to track circuit ids 1 through 255 */
struct route_table *ext_info[REDIST_PROTOCOL_COUNT];
struct ldp_sync_info_cmd ldp_sync_cmd; /* MPLS LDP-IGP Sync */
};
extern struct isis_master *im;
@ -275,6 +277,7 @@ extern unsigned long debug_flooding;
extern unsigned long debug_bfd;
extern unsigned long debug_tx_queue;
extern unsigned long debug_sr;
extern unsigned long debug_ldp_sync;
#define DEBUG_ADJ_PACKETS (1<<0)
#define DEBUG_SNP_PACKETS (1<<1)
@ -289,6 +292,7 @@ extern unsigned long debug_sr;
#define DEBUG_BFD (1<<10)
#define DEBUG_TX_QUEUE (1<<11)
#define DEBUG_SR (1<<12)
#define DEBUG_LDP_SYNC (1 << 13)
/* Debug related macro. */
#define IS_DEBUG_ADJ_PACKETS (debug_adj_pkt & DEBUG_ADJ_PACKETS)
@ -304,6 +308,7 @@ extern unsigned long debug_sr;
#define IS_DEBUG_BFD (debug_bfd & DEBUG_BFD)
#define IS_DEBUG_TX_QUEUE (debug_tx_queue & DEBUG_TX_QUEUE)
#define IS_DEBUG_SR (debug_sr & DEBUG_SR)
#define IS_DEBUG_LDP_SYNC (debug_ldp_sync & DEBUG_LDP_SYNC)
#define lsp_debug(...) \
do { \

View File

@ -8,6 +8,7 @@ sbin_PROGRAMS += isisd/isisd
dist_examples_DATA += isisd/isisd.conf.sample
vtysh_scan += \
isisd/isis_cli.c \
isisd/isis_ldp_sync.c \
isisd/isis_redist.c \
isisd/isis_spf.c \
isisd/isis_te.c \
@ -36,6 +37,7 @@ noinst_HEADERS += \
isisd/isis_errors.h \
isisd/isis_events.h \
isisd/isis_flags.h \
isisd/isis_ldp_sync.h \
isisd/isis_lsp.h \
isisd/isis_memory.h \
isisd/isis_misc.h \
@ -69,6 +71,7 @@ LIBISIS_SOURCES = \
isisd/isis_errors.c \
isisd/isis_events.c \
isisd/isis_flags.c \
isisd/isis_ldp_sync.c \
isisd/isis_lsp.c \
isisd/isis_memory.c \
isisd/isis_misc.c \

View File

@ -125,6 +125,9 @@ adj_del(struct adj *adj, uint32_t notif_status)
switch (adj->source.type) {
case HELLO_LINK:
RB_REMOVE(ia_adj_head, &adj->source.link.ia->adj_tree, adj);
if (nbr)
ldp_sync_fsm_adj_event(adj, LDP_SYNC_EVT_ADJ_DEL);
break;
case HELLO_TARGETED:
adj->source.target->adj = NULL;

View File

@ -263,6 +263,9 @@ control_dispatch_imsg(struct thread *thread)
nbr_clear_ctl(imsg.data);
break;
case IMSG_CTL_SHOW_LDP_SYNC:
ldpe_ldp_sync_ctl(c);
break;
case IMSG_CTL_LOG_VERBOSE:
/* ignore */
break;

View File

@ -378,6 +378,7 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *msg, int af,
adj->nbr = nbr;
RB_INSERT(nbr_adj_head, &nbr->adj_tree, adj);
}
ldp_sync_fsm_adj_event(adj, LDP_SYNC_EVT_ADJ_NEW);
}
adj->ds_tlv = ds_tlv;

View File

@ -23,6 +23,7 @@
#include "ldpd.h"
#include "ldpe.h"
#include "log.h"
#include "ldp_debug.h"
#include "sockopt.h"
@ -40,6 +41,17 @@ static int if_leave_ipv4_group(struct iface *, struct in_addr *);
static int if_join_ipv6_group(struct iface *, struct in6_addr *);
static int if_leave_ipv6_group(struct iface *, struct in6_addr *);
static int ldp_sync_fsm_init(struct iface *iface, int state);
static int ldp_sync_act_iface_start_sync(struct iface *iface);
static int iface_wait_for_ldp_sync_timer(struct thread *thread);
static void start_wait_for_ldp_sync_timer(struct iface *iface);
static void stop_wait_for_ldp_sync_timer(struct iface *iface);
static int ldp_sync_act_ldp_start_sync(struct iface *iface);
static int ldp_sync_act_ldp_complete_sync(struct iface *iface);
static int iface_to_oper_nbr_count(struct iface *iface, unsigned int type);
static void ldp_sync_get_peer_ldp_id(struct iface *iface,
struct in_addr *peer_ldp_id);
RB_GENERATE(iface_head, iface, entry, iface_compare)
static __inline int
@ -87,6 +99,9 @@ ldpe_if_init(struct iface *iface)
iface->ipv6.iface = iface;
iface->ipv6.state = IF_STA_DOWN;
RB_INIT(ia_adj_head, &iface->ipv6.adj_tree);
/* LGP IGP Sync */
ldp_sync_fsm_init(iface, LDP_SYNC_STA_NOT_ACH);
}
void
@ -96,6 +111,8 @@ ldpe_if_exit(struct iface *iface)
log_debug("%s: interface %s", __func__, iface->name);
ldp_sync_fsm(iface, LDP_SYNC_EVT_CONFIG_LDP_OFF);
if (iface->ipv4.state == IF_STA_ACTIVE)
if_reset(iface, AF_INET);
if (iface->ipv6.state == IF_STA_ACTIVE)
@ -138,6 +155,10 @@ if_update_info(struct iface *iface, struct kif *kif)
kif->flags & IFF_MULTICAST)
iface->type = IF_TYPE_BROADCAST;
if (ldpd_process == PROC_LDP_ENGINE && iface->operative &&
!kif->operative)
ldp_sync_fsm(iface, LDP_SYNC_EVT_IFACE_SHUTDOWN);
/* get index and flags */
iface->ifindex = kif->ifindex;
iface->operative = kif->operative;
@ -426,6 +447,12 @@ if_get_hello_interval(struct iface_af *ia)
return (leconf->lhello_interval);
}
uint16_t
if_get_wait_for_sync_interval(void)
{
return (leconf->wait_for_sync_interval);
}
/* timers */
/* ARGSUSED */
static int
@ -484,6 +511,55 @@ if_to_ctl(struct iface_af *ia)
return (&ictl);
}
static void
ldp_sync_get_peer_ldp_id(struct iface *iface, struct in_addr *peer_ldp_id)
{
struct iface_af *ia;
struct adj *adj;
if (iface->ipv4.state == IF_STA_ACTIVE) {
ia = iface_af_get(iface, AF_INET);
RB_FOREACH(adj, ia_adj_head, &ia->adj_tree)
if (adj->nbr && adj->nbr->state == NBR_STA_OPER) {
*peer_ldp_id = adj->nbr->id;
return;
}
}
if (iface->ipv6.state == IF_STA_ACTIVE) {
ia = iface_af_get(iface, AF_INET6);
RB_FOREACH(adj, ia_adj_head, &ia->adj_tree)
if (adj->nbr && adj->nbr->state == NBR_STA_OPER) {
*peer_ldp_id = adj->nbr->id;
return;
}
}
}
struct ctl_ldp_sync *
ldp_sync_to_ctl(struct iface *iface)
{
static struct ctl_ldp_sync ictl;
memcpy(ictl.name, iface->name, sizeof(ictl.name));
ictl.ifindex = iface->ifindex;
ictl.in_sync = (iface->ldp_sync.state == LDP_SYNC_STA_ACH);
ictl.wait_time = if_get_wait_for_sync_interval();
ictl.timer_running = iface->ldp_sync.wait_for_sync_timer ? true : false;
if (iface->ldp_sync.wait_for_sync_timer)
ictl.wait_time_remaining =
thread_timer_remain_second(iface->ldp_sync.wait_for_sync_timer);
else
ictl.wait_time_remaining = 0;
memset(&ictl.peer_ldp_id, 0, sizeof(ictl.peer_ldp_id));
ldp_sync_get_peer_ldp_id(iface, &ictl.peer_ldp_id);
return (&ictl);
}
/* multicast membership sockopts */
in_addr_t
if_get_ipv4_addr(struct iface *iface)
@ -576,3 +652,344 @@ if_leave_ipv6_group(struct iface *iface, struct in6_addr *addr)
return (0);
}
const struct {
int state;
enum ldp_sync_event event;
enum ldp_sync_action action;
int new_state;
} ldp_sync_fsm_tbl[] = {
/* current state event that happened action to take resulting state */
/* LDP IGP Sync not achieved */
{LDP_SYNC_STA_NOT_ACH, LDP_SYNC_EVT_LDP_SYNC_START, LDP_SYNC_ACT_LDP_START_SYNC, 0},
{LDP_SYNC_STA_NOT_ACH, LDP_SYNC_EVT_LDP_SYNC_COMPLETE, LDP_SYNC_ACT_LDP_COMPLETE_SYNC, LDP_SYNC_STA_ACH},
{LDP_SYNC_STA_NOT_ACH, LDP_SYNC_EVT_CONFIG_LDP_OFF, LDP_SYNC_ACT_CONFIG_LDP_OFF, 0},
{LDP_SYNC_STA_NOT_ACH, LDP_SYNC_EVT_IFACE_SHUTDOWN, LDP_SYNC_ACT_IFACE_SHUTDOWN, 0},
{LDP_SYNC_STA_NOT_ACH, LDP_SYNC_EVT_SESSION_CLOSE, LDP_SYNC_ACT_NOTHING, 0},
{LDP_SYNC_STA_NOT_ACH, LDP_SYNC_EVT_ADJ_DEL, LDP_SYNC_ACT_NOTHING, 0},
{LDP_SYNC_STA_NOT_ACH, LDP_SYNC_EVT_ADJ_NEW, LDP_SYNC_ACT_NOTHING, 0},
/* LDP IGP Sync achieved */
{LDP_SYNC_STA_ACH, LDP_SYNC_EVT_CONFIG_LDP_OFF, LDP_SYNC_ACT_CONFIG_LDP_OFF, LDP_SYNC_STA_NOT_ACH},
{LDP_SYNC_STA_ACH, LDP_SYNC_EVT_LDP_SYNC_COMPLETE, LDP_SYNC_ACT_NOTHING, 0},
{LDP_SYNC_STA_ACH, LDP_SYNC_EVT_LDP_SYNC_START, LDP_SYNC_ACT_NOTHING, 0},
{LDP_SYNC_STA_ACH, LDP_SYNC_EVT_IFACE_SHUTDOWN, LDP_SYNC_ACT_IFACE_SHUTDOWN, LDP_SYNC_STA_NOT_ACH},
{LDP_SYNC_STA_ACH, LDP_SYNC_EVT_SESSION_CLOSE, LDP_SYNC_ACT_IFACE_START_SYNC, LDP_SYNC_STA_NOT_ACH},
{LDP_SYNC_STA_ACH, LDP_SYNC_EVT_ADJ_DEL, LDP_SYNC_ACT_IFACE_START_SYNC, LDP_SYNC_STA_NOT_ACH},
{LDP_SYNC_STA_ACH, LDP_SYNC_EVT_ADJ_NEW, LDP_SYNC_ACT_NOTHING, 0},
{-1, LDP_SYNC_EVT_NOTHING, LDP_SYNC_ACT_NOTHING, 0},
};
const char * const ldp_sync_event_names[] = {
"NOTHING",
"LDP SYNC START",
"LDP SYNC COMPLETE",
"CONFIG LDP OFF",
"IFACE SYNC START (ADJ DEL)",
"IFACE SYNC START (ADJ NEW)",
"IFACE SYNC START (SESSION CLOSE)",
"IFACE SYNC START (CONFIG LDP ON)",
"IFACE SHUTDOWN",
"N/A"
};
const char * const ldp_sync_action_names[] = {
"NOTHING",
"IFACE SYNC START",
"LDP START SYNC",
"LDP COMPLETE SYNC",
"CONFIG LDP OFF",
"IFACE SHUTDOWN",
"N/A"
};
const char *
ldp_sync_state_name(int state)
{
switch (state) {
case LDP_SYNC_STA_NOT_ACH:
return ("NOT ACHIEVED");
case LDP_SYNC_STA_ACH:
return ("ACHIEVED");
default:
return ("UNKNOWN");
}
}
static int
send_ldp_sync_state_update(char *name, int ifindex, int sync_start)
{
debug_evt_ldp_sync("%s: interface %s (%d), sync_start=%d",
__func__, name, ifindex, sync_start);
struct ldp_igp_sync_if_state state;
state.ifindex = ifindex;
state.sync_start = sync_start;
return ldpe_imsg_compose_parent(IMSG_LDP_SYNC_IF_STATE_UPDATE,
getpid(), &state, sizeof(state));
}
static int
ldp_sync_act_iface_start_sync(struct iface *iface)
{
send_ldp_sync_state_update(iface->name, iface->ifindex, true);
return (0);
}
static int
iface_wait_for_ldp_sync_timer(struct thread *thread)
{
struct iface *iface = THREAD_ARG(thread);
ldp_sync_fsm(iface, LDP_SYNC_EVT_LDP_SYNC_COMPLETE);
return (0);
}
static void start_wait_for_ldp_sync_timer(struct iface *iface)
{
if (iface->ldp_sync.wait_for_sync_timer)
return;
THREAD_TIMER_OFF(iface->ldp_sync.wait_for_sync_timer);
iface->ldp_sync.wait_for_sync_timer = NULL;
thread_add_timer(master, iface_wait_for_ldp_sync_timer, iface,
if_get_wait_for_sync_interval(),
&iface->ldp_sync.wait_for_sync_timer);
}
static void stop_wait_for_ldp_sync_timer(struct iface *iface)
{
THREAD_TIMER_OFF(iface->ldp_sync.wait_for_sync_timer);
iface->ldp_sync.wait_for_sync_timer = NULL;
}
static int
ldp_sync_act_ldp_start_sync(struct iface *iface)
{
start_wait_for_ldp_sync_timer(iface);
return 0;
}
static int
ldp_sync_act_ldp_complete_sync(struct iface *iface)
{
send_ldp_sync_state_update(iface->name, iface->ifindex, false);
return 0;
}
static int
iface_to_oper_nbr_count(struct iface *iface, unsigned int type)
{
int oper_nbr_count = 0;
struct adj *adj;
RB_FOREACH(adj, ia_adj_head, &iface->ipv4.adj_tree) {
if (type == adj->source.type && adj->nbr &&
adj->nbr->state == NBR_STA_OPER)
oper_nbr_count++;
}
RB_FOREACH(adj, ia_adj_head, &iface->ipv6.adj_tree) {
if (type == adj->source.type && adj->nbr &&
adj->nbr->state == NBR_STA_OPER)
oper_nbr_count++;
}
return oper_nbr_count;
}
int
ldp_sync_fsm_adj_event(struct adj *adj, enum ldp_sync_event event)
{
if (adj->source.type != HELLO_LINK)
return -1;
struct iface *iface = adj->source.link.ia->iface;
if (!iface->operative)
return 0;
if (event == LDP_SYNC_EVT_ADJ_NEW) {
struct nbr *nbr = adj->nbr;
if (nbr && nbr->state == NBR_STA_OPER) {
event = LDP_SYNC_EVT_LDP_SYNC_START;
}
} else if (event == LDP_SYNC_EVT_ADJ_DEL) {
/* Ignore if an operational neighbor exists.
*/
int oper_nbr_count = iface_to_oper_nbr_count(iface, HELLO_LINK);
if (oper_nbr_count > 0)
return 0;
}
debug_evt_ldp_sync("%s: event %s, "
"adj iface %s (%d) lsr-id %s "
"source address %s transport address %s",
__func__, ldp_sync_event_names[event],
adj->source.link.ia->iface->name,
adj->source.link.ia->iface->ifindex,
inet_ntoa(adj->lsr_id),
log_addr(adj_get_af(adj), &adj->source.link.src_addr),
log_addr(adj_get_af(adj), &adj->trans_addr));
return ldp_sync_fsm(iface, event);
}
int
ldp_sync_fsm_nbr_event(struct nbr *nbr, enum ldp_sync_event event)
{
struct adj *adj;
struct iface *iface = NULL;
RB_FOREACH(adj, nbr_adj_head, &nbr->adj_tree) {
if (HELLO_LINK != adj->source.type)
continue;
iface = adj->source.link.ia->iface;
if (!iface || !iface->operative)
continue;
int oper_nbr_count = iface_to_oper_nbr_count(iface, HELLO_LINK);
if (event == LDP_SYNC_EVT_SESSION_CLOSE && oper_nbr_count > 0)
/* Ignore if an operational neighbor exists.
*/
continue;
debug_evt_ldp_sync("%s: event %s, iface %s, lsr-id %s",
__func__, ldp_sync_event_names[event],
iface->name, inet_ntoa(nbr->id));
ldp_sync_fsm(iface, event);
}
return 0;
}
int
ldp_sync_fsm_state_req(struct ldp_igp_sync_if_state_req *state_req)
{
debug_evt_ldp_sync("%s: interface %s (%d) proto %s",
__func__, state_req->name, state_req->ifindex,
zebra_route_string(state_req->proto));
struct iface *iface = if_lookup_name(leconf, state_req->name);
if (!iface) {
debug_evt_ldp_sync("%s: Warning: Ignoring LDP IGP SYNC "
"interface state request for interface %s (%d). "
"Interface does not exist in LDP.",
__func__, state_req->name, state_req->ifindex);
return 0;
}
return send_ldp_sync_state_update(state_req->name,
state_req->ifindex,
(iface->ldp_sync.state != LDP_SYNC_STA_ACH));
}
static int
ldp_sync_fsm_init(struct iface *iface, int state)
{
int old_state = iface->ldp_sync.state;
iface->ldp_sync.state = state;
stop_wait_for_ldp_sync_timer(iface);
send_ldp_sync_state_update(iface->name, iface->ifindex,
(iface->ldp_sync.state != LDP_SYNC_STA_ACH));
if (old_state != iface->ldp_sync.state) {
debug_evt_ldp_sync("%s: resulted in "
"changing state for interface %s (%d) from %s to %s",
__func__,
iface->name, iface->ifindex,
ldp_sync_state_name(old_state),
ldp_sync_state_name(iface->ldp_sync.state));
}
return 0;
}
int
ldp_sync_fsm(struct iface *iface, enum ldp_sync_event event)
{
int old_state = iface->ldp_sync.state;
int new_state = 0;
int i;
for (i = 0; ldp_sync_fsm_tbl[i].state != -1; i++)
if ((ldp_sync_fsm_tbl[i].state & old_state) &&
(ldp_sync_fsm_tbl[i].event == event)) {
new_state = ldp_sync_fsm_tbl[i].new_state;
break;
}
if (ldp_sync_fsm_tbl[i].state == -1) {
/* event outside of the defined fsm, ignore it. */
log_warnx("%s: interface %s, event %s not expected in "
"state %s ", __func__, iface->name,
ldp_sync_event_names[event],
ldp_sync_state_name(old_state));
return (0);
}
if (new_state != 0)
iface->ldp_sync.state = new_state;
switch (ldp_sync_fsm_tbl[i].action) {
case LDP_SYNC_ACT_IFACE_START_SYNC:
ldp_sync_act_iface_start_sync(iface);
break;
case LDP_SYNC_ACT_LDP_START_SYNC:
ldp_sync_act_ldp_start_sync(iface);
break;
case LDP_SYNC_ACT_LDP_COMPLETE_SYNC:
ldp_sync_act_ldp_complete_sync(iface);
break;
case LDP_SYNC_ACT_CONFIG_LDP_OFF:
ldp_sync_fsm_init(iface, LDP_SYNC_STA_NOT_ACH);
break;
case LDP_SYNC_ACT_IFACE_SHUTDOWN:
ldp_sync_fsm_init(iface, iface->ldp_sync.state);
break;
case LDP_SYNC_ACT_NOTHING:
/* do nothing */
break;
}
if (old_state != iface->ldp_sync.state) {
debug_evt_ldp_sync("%s: event %s resulted in action %s "
"for interface %s, changing state from %s to %s",
__func__, ldp_sync_event_names[event],
ldp_sync_action_names[ldp_sync_fsm_tbl[i].action],
iface->name, ldp_sync_state_name(old_state),
ldp_sync_state_name(iface->ldp_sync.state));
} else {
debug_evt_ldp_sync("%s: event %s resulted in action %s "
"for interface %s, remaining in state %s",
__func__, ldp_sync_event_names[event],
ldp_sync_action_names[ldp_sync_fsm_tbl[i].action],
iface->name,
ldp_sync_state_name(iface->ldp_sync.state));
}
return (0);
}
void
ldp_sync_fsm_reset_all(void)
{
struct iface *iface;
RB_FOREACH(iface, iface_head, &leconf->iface_tree)
ldp_sync_fsm(iface, LDP_SYNC_EVT_CONFIG_LDP_OFF);
}

View File

@ -51,6 +51,8 @@
#define INIT_DELAY_TMR 15
#define MAX_DELAY_TMR 120
#define DFLT_WAIT_FOR_SYNC 10
#define MIN_PWID_ID 1
#define MAX_PWID_ID 0xffffffff

View File

@ -99,6 +99,11 @@ ldp_vty_debug(struct vty *vty, const char *negate, const char *type_str,
DEBUG_ON(msg, LDP_DEBUG_MSG_SEND_ALL);
}
}
} else if (strcmp(type_str, "sync") == 0) {
if (negate)
DEBUG_OFF(sync, LDP_DEBUG_SYNC);
else
DEBUG_ON(sync, LDP_DEBUG_SYNC);
} else if (strcmp(type_str, "zebra") == 0) {
if (negate)
DEBUG_OFF(zebra, LDP_DEBUG_ZEBRA);
@ -137,6 +142,8 @@ ldp_vty_show_debugging(struct vty *vty)
" LDP detailed messages debugging is on (outbound)\n");
else if (LDP_DEBUG(msg, LDP_DEBUG_MSG_SEND))
vty_out (vty," LDP messages debugging is on (outbound)\n");
if (LDP_DEBUG(sync, LDP_DEBUG_SYNC))
vty_out (vty, " LDP sync debugging is on\n");
if (LDP_DEBUG(zebra, LDP_DEBUG_ZEBRA))
vty_out (vty, " LDP zebra debugging is on\n");
vty_out (vty, "\n");
@ -195,5 +202,10 @@ ldp_debug_config_write(struct vty *vty)
write = 1;
}
if (CONF_LDP_DEBUG(sync, LDP_DEBUG_SYNC)) {
vty_out (vty, "debug mpls ldp sync\n");
write = 1;
}
return (write);
}

View File

@ -42,6 +42,10 @@ struct ldp_debug {
int zebra;
#define LDP_DEBUG_ZEBRA 0x01
int sync;
#define LDP_DEBUG_SYNC 0x01
};
extern struct ldp_debug conf_ldp_debug;
extern struct ldp_debug ldp_debug;
@ -143,4 +147,10 @@ do { \
log_debug("zebra[out]: " emsg, __VA_ARGS__); \
} while (0)
#define debug_evt_ldp_sync(emsg, ...) \
do { \
if (LDP_DEBUG(sync, LDP_DEBUG_SYNC)) \
log_debug("sync: " emsg, __VA_ARGS__); \
} while (0)
#endif /* _LDP_DEBUG_H_ */

View File

@ -50,6 +50,7 @@ int ldp_vty_label_accept(struct vty *, const char *, const char *, const char *
int ldp_vty_ttl_security(struct vty *, const char *);
int ldp_vty_router_id(struct vty *, const char *, struct in_addr);
int ldp_vty_ordered_control(struct vty *, const char *);
int ldp_vty_wait_for_sync_interval(struct vty *, const char *, long);
int ldp_vty_ds_cisco_interop(struct vty *, const char *);
int ldp_vty_trans_pref_ipv4(struct vty *, const char *);
int ldp_vty_neighbor_password(struct vty *, const char *, struct in_addr, const char *);
@ -73,6 +74,7 @@ int ldp_vty_show_discovery(struct vty *, const char *, const char *, const char
int ldp_vty_show_interface(struct vty *, const char *, const char *);
int ldp_vty_show_capabilities(struct vty *, const char *);
int ldp_vty_show_neighbor(struct vty *, const char *, int, const char *, const char *);
int ldp_vty_show_ldp_sync(struct vty *, const char *);
int ldp_vty_show_atom_binding(struct vty *, const char *, unsigned long,
unsigned long, const char *);
int ldp_vty_show_atom_vc(struct vty *, const char *, const char *,

View File

@ -230,6 +230,17 @@ DEFPY (ldp_ordered_control,
return (ldp_vty_ordered_control(vty, no));
}
DEFPY (ldp_wait_for_sync,
ldp_wait_for_sync_cmd,
"[no] wait-for-sync (1-10000)$waitforsync",
NO_STR
"Time to wait for LDP-IGP Sync to complete label exchange\n"
"Time (seconds)\n")
{
return (ldp_vty_wait_for_sync_interval(vty, no, waitforsync));
}
DEFPY (ldp_discovery_targeted_hello_accept,
ldp_discovery_targeted_hello_accept_cmd,
"[no] discovery targeted-hello accept [from <(1-199)|(1300-2699)|WORD>$from_acl]",
@ -547,7 +558,7 @@ DEFPY (ldp_debug_mpls_ldp_discovery_hello,
DEFPY (ldp_debug_mpls_ldp_type,
ldp_debug_mpls_ldp_type_cmd,
"[no] debug mpls ldp <errors|event|labels|zebra>$type",
"[no] debug mpls ldp <errors|event|labels|sync|zebra>$type",
NO_STR
"Debugging functions\n"
"MPLS information\n"
@ -555,6 +566,7 @@ DEFPY (ldp_debug_mpls_ldp_type,
"Errors\n"
"LDP event information\n"
"LDP label allocation information\n"
"LDP sync information\n"
"LDP zebra information\n")
{
return (ldp_vty_debug(vty, no, type, NULL, NULL));
@ -695,6 +707,18 @@ DEFPY (ldp_show_mpls_ldp_neighbor_capabilities,
return (ldp_vty_show_neighbor(vty, lsr_id_str, 1, NULL, json));
}
DEFPY (ldp_show_mpls_ldp_igp_sync,
ldp_show_mpls_ldp_igp_sync_cmd,
"show mpls ldp igp-sync [json]$json",
"Show mpls ldp ldp-sync information\n"
"MPLS information\n"
"Label Distribution Protocol\n"
"LDP-IGP Sync information\n"
JSON_STR)
{
return (ldp_vty_show_ldp_sync(vty, json));
}
DEFPY (ldp_show_l2vpn_atom_binding,
ldp_show_l2vpn_atom_binding_cmd,
"show l2vpn atom binding\
@ -819,6 +843,7 @@ ldp_vty_init (void)
install_element(LDP_NODE, &ldp_neighbor_ttl_security_cmd);
install_element(LDP_NODE, &ldp_router_id_cmd);
install_element(LDP_NODE, &ldp_ordered_control_cmd);
install_element(LDP_NODE, &ldp_wait_for_sync_cmd);
install_element(LDP_IPV4_NODE, &ldp_discovery_link_holdtime_cmd);
install_element(LDP_IPV4_NODE, &ldp_discovery_targeted_holdtime_cmd);
@ -888,4 +913,5 @@ ldp_vty_init (void)
install_element(VIEW_NODE, &ldp_show_l2vpn_atom_binding_cmd);
install_element(VIEW_NODE, &ldp_show_l2vpn_atom_vc_cmd);
install_element(VIEW_NODE, &ldp_show_debugging_mpls_ldp_cmd);
install_element(VIEW_NODE, &ldp_show_mpls_ldp_igp_sync_cmd);
}

View File

@ -285,6 +285,11 @@ ldp_config_write(struct vty *vty)
if (ldpd_conf->flags & F_LDPD_ORDERED_CONTROL)
vty_out (vty, " ordered-control\n");
if (ldpd_conf->wait_for_sync_interval != DFLT_WAIT_FOR_SYNC &&
ldpd_conf->wait_for_sync_interval != 0)
vty_out (vty, " wait-for-sync %u\n",
ldpd_conf->wait_for_sync_interval);
RB_FOREACH(nbrp, nbrp_head, &ldpd_conf->nbrp_tree) {
if (nbrp->flags & F_NBRP_KEEPALIVE)
vty_out (vty, " neighbor %s session holdtime %u\n",
@ -477,7 +482,6 @@ int ldp_vty_disc_holdtime(struct vty *vty, const char *negate,
struct iface *iface;
struct iface_af *ia;
int af;
switch (vty->node) {
case LDP_NODE:
if (negate) {
@ -1014,6 +1018,24 @@ ldp_vty_ordered_control(struct vty *vty, const char *negate)
return (CMD_SUCCESS);
}
int ldp_vty_wait_for_sync_interval(struct vty *vty, const char *negate,
long secs)
{
switch (vty->node) {
case LDP_NODE:
if (negate)
vty_conf->wait_for_sync_interval = DFLT_WAIT_FOR_SYNC;
else
vty_conf->wait_for_sync_interval = secs;
ldp_config_apply(vty, vty_conf);
break;
default:
fatalx("ldp_vty_wait_for_sync_interval: unexpected node");
}
return (CMD_SUCCESS);
}
int
ldp_vty_ds_cisco_interop(struct vty *vty, const char * negate)
{

View File

@ -37,7 +37,8 @@ enum show_command {
SHOW_NBR,
SHOW_LIB,
SHOW_L2VPN_PW,
SHOW_L2VPN_BINDING
SHOW_L2VPN_BINDING,
SHOW_LDP_SYNC
};
struct show_params {
@ -86,6 +87,10 @@ static void show_discovery_detail_adj_json(json_object *,
struct ctl_adj *);
static int show_discovery_detail_msg_json(struct imsg *,
struct show_params *, json_object *);
static int show_ldp_sync_msg(struct vty *, struct imsg *,
struct show_params *);
static int show_ldp_sync_msg_json(struct imsg *,
struct show_params *, json_object *);
static int show_nbr_msg(struct vty *, struct imsg *,
struct show_params *);
@ -122,7 +127,6 @@ static int show_l2vpn_pw_msg(struct vty *, struct imsg *,
struct show_params *);
static int show_l2vpn_pw_msg_json(struct imsg *,
struct show_params *, json_object *);
static int ldp_vty_connect(struct imsgbuf *);
static int ldp_vty_dispatch_msg(struct vty *, struct imsg *,
enum show_command, struct show_params *,
json_object *);
@ -206,6 +210,87 @@ show_interface_msg_json(struct imsg *imsg, struct show_params *params,
return (0);
}
static int
show_ldp_sync_msg(struct vty *vty, struct imsg *imsg,
struct show_params *params)
{
struct ctl_ldp_sync *iface;
switch (imsg->hdr.type) {
case IMSG_CTL_SHOW_LDP_SYNC:
iface = imsg->data;
vty_out (vty, "%s:\n", iface->name);
if (iface->in_sync)
vty_out (vty, " Status: initial label exchange complete\n");
else
vty_out (vty, " Status: label exchange not complete\n");
if (iface->timer_running) {
vty_out (vty, " Wait time: %d seconds (%d seconds left)\n",
iface->wait_time, iface->wait_time_remaining);
vty_out (vty, " Timer is running\n");
} else {
vty_out (vty, " Wait time: %d seconds\n",
iface->wait_time);
vty_out (vty, " Timer is not running\n");
}
if (iface->peer_ldp_id.s_addr)
vty_out (vty, " Peer LDP Identifier: %s:0\n",
inet_ntoa(iface->peer_ldp_id));
break;
case IMSG_CTL_END:
return (1);
default:
break;
}
return (0);
}
static int
show_ldp_sync_msg_json(struct imsg *imsg, struct show_params *params,
json_object *json)
{
struct ctl_ldp_sync *iface;
json_object *json_iface;
switch (imsg->hdr.type) {
case IMSG_CTL_SHOW_LDP_SYNC:
iface = imsg->data;
json_iface = json_object_new_object();
json_object_string_add(json_iface, "state",
iface->in_sync
? "labelExchangeComplete"
: "labelExchangeNotComplete");
json_object_int_add(json_iface, "waitTime",
iface->wait_time);
json_object_int_add(json_iface, "waitTimeRemaining",
iface->wait_time_remaining);
if (iface->timer_running)
json_object_boolean_true_add(json_iface, "timerRunning");
else
json_object_boolean_false_add(json_iface, "timerRunning");
json_object_string_add(json_iface, "peerLdpId",
iface->peer_ldp_id.s_addr ?
inet_ntoa(iface->peer_ldp_id) : "");
json_object_object_add(json, iface->name, json_iface);
break;
case IMSG_CTL_END:
return (1);
default:
break;
}
return (0);
}
static int
show_discovery_msg(struct vty *vty, struct imsg *imsg,
struct show_params *params)
@ -1436,6 +1521,20 @@ ldp_vty_dispatch_iface(struct vty *vty, struct imsg *imsg,
return (ret);
}
static int
ldp_vty_dispatch_ldp_sync(struct vty *vty, struct imsg *imsg,
struct show_params *params, json_object *json)
{
int ret;
if (params->json)
ret = show_ldp_sync_msg_json(imsg, params, json);
else
ret = show_ldp_sync_msg(vty, imsg, params);
return (ret);
}
static int
ldp_vty_dispatch_disc(struct vty *vty, struct imsg *imsg,
struct show_params *params, json_object *json)
@ -1684,6 +1783,8 @@ ldp_vty_dispatch_msg(struct vty *vty, struct imsg *imsg, enum show_command cmd,
case SHOW_L2VPN_BINDING:
return (ldp_vty_dispatch_l2vpn_binding(vty, imsg, params,
json));
case SHOW_LDP_SYNC:
return (ldp_vty_dispatch_ldp_sync(vty, imsg, params, json));
default:
return (0);
}
@ -1945,6 +2046,22 @@ ldp_vty_show_neighbor(struct vty *vty, const char *lsr_id, int capabilities,
return (ldp_vty_dispatch(vty, &ibuf, SHOW_NBR, &params));
}
int
ldp_vty_show_ldp_sync(struct vty *vty, const char *json)
{
struct imsgbuf ibuf;
struct show_params params;
if (ldp_vty_connect(&ibuf) < 0)
return (CMD_WARNING);
memset(&params, 0, sizeof(params));
params.json = (json) ? 1 : 0;
imsg_compose(&ibuf, IMSG_CTL_SHOW_LDP_SYNC, 0, 0, -1, NULL, 0);
return (ldp_vty_dispatch(vty, &ibuf, SHOW_LDP_SYNC, &params));
}
int
ldp_vty_show_atom_binding(struct vty *vty, const char *peer,
unsigned long local_label, unsigned long remote_label, const char *json)

View File

@ -31,6 +31,7 @@
#include "ldpd.h"
#include "ldpe.h"
#include "lde.h"
#include "ldp_sync.h"
#include "log.h"
#include "ldp_debug.h"
@ -46,6 +47,14 @@ static int ldp_zebra_read_pw_status_update(ZAPI_CALLBACK_ARGS);
static void ldp_zebra_connected(struct zclient *);
static void ldp_zebra_filter_update(struct access_list *access);
static void ldp_zebra_opaque_register(void);
static void ldp_zebra_opaque_unregister(void);
static int ldp_sync_zebra_send_announce(void);
static int ldp_zebra_opaque_msg_handler(ZAPI_CALLBACK_ARGS);
static void ldp_sync_zebra_start_hello_timer(void);
static int ldp_sync_zebra_hello(struct thread *thread);
static void ldp_sync_zebra_init(void);
static struct zclient *zclient;
static void
@ -103,6 +112,95 @@ pw2zpw(struct l2vpn_pw *pw, struct zapi_pw *zpw)
sizeof(zpw->data.ldp.vpn_name));
}
static void
ldp_zebra_opaque_register(void)
{
zclient_register_opaque(zclient, LDP_IGP_SYNC_IF_STATE_REQUEST);
}
static void
ldp_zebra_opaque_unregister(void)
{
zclient_unregister_opaque(zclient, LDP_IGP_SYNC_IF_STATE_REQUEST);
}
int
ldp_sync_zebra_send_state_update(struct ldp_igp_sync_if_state *state)
{
return zclient_send_opaque(zclient, LDP_IGP_SYNC_IF_STATE_UPDATE,
(const uint8_t *) state, sizeof(*state));
}
static int
ldp_sync_zebra_send_announce(void)
{
struct ldp_igp_sync_announce announce;
announce.proto = ZEBRA_ROUTE_LDP;
return zclient_send_opaque(zclient, LDP_IGP_SYNC_ANNOUNCE_UPDATE,
(const uint8_t *) &announce, sizeof(announce));
}
static int
ldp_zebra_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
{
struct stream *s;
struct zapi_opaque_msg info;
struct ldp_igp_sync_if_state_req state_req;
s = zclient->ibuf;
if (zclient_opaque_decode(s, &info) != 0)
return -1;
switch (info.type) {
case LDP_IGP_SYNC_IF_STATE_REQUEST:
STREAM_GET(&state_req, s, sizeof(state_req));
main_imsg_compose_ldpe(IMSG_LDP_SYNC_IF_STATE_REQUEST, 0, &state_req,
sizeof(state_req));
break;
default:
break;
}
stream_failure:
return 0;
}
static void
ldp_sync_zebra_start_hello_timer(void)
{
thread_add_timer_msec(master, ldp_sync_zebra_hello, NULL, 250, NULL);
}
static int
ldp_sync_zebra_hello(struct thread *thread)
{
static unsigned int sequence = 0;
struct ldp_igp_sync_hello hello;
sequence++;
hello.proto = ZEBRA_ROUTE_LDP;
hello.sequence = sequence;
zclient_send_opaque(zclient, LDP_IGP_SYNC_HELLO_UPDATE,
(const uint8_t *) &hello, sizeof(hello));
ldp_sync_zebra_start_hello_timer();
return (0);
}
static void
ldp_sync_zebra_init(void)
{
ldp_sync_zebra_send_announce();
ldp_sync_zebra_start_hello_timer();
}
static int
ldp_zebra_send_mpls_labels(int cmd, struct kroute *kr)
{
@ -299,7 +397,7 @@ ldp_ifp_destroy(struct interface *ifp)
}
static int
ldp_interface_status_change_helper(struct interface *ifp)
ldp_interface_status_change(struct interface *ifp)
{
struct listnode *node;
struct connected *ifc;
@ -330,12 +428,12 @@ ldp_interface_status_change_helper(struct interface *ifp)
static int ldp_ifp_up(struct interface *ifp)
{
return ldp_interface_status_change_helper(ifp);
return ldp_interface_status_change(ifp);
}
static int ldp_ifp_down(struct interface *ifp)
{
return ldp_interface_status_change_helper(ifp);
return ldp_interface_status_change(ifp);
}
static int
@ -525,6 +623,10 @@ ldp_zebra_connected(struct zclient *zclient)
ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT);
zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6,
ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT);
ldp_zebra_opaque_register();
ldp_sync_zebra_init();
}
static void
@ -563,6 +665,7 @@ ldp_zebra_init(struct thread_master *master)
zclient->redistribute_route_add = ldp_zebra_read_route;
zclient->redistribute_route_del = ldp_zebra_read_route;
zclient->pw_status_update = ldp_zebra_read_pw_status_update;
zclient->opaque_msg_handler = ldp_zebra_opaque_msg_handler;
/* Access list initialize. */
access_list_add_hook(ldp_zebra_filter_update);
@ -572,6 +675,7 @@ ldp_zebra_init(struct thread_master *master)
void
ldp_zebra_destroy(void)
{
ldp_zebra_opaque_unregister();
zclient_stop(zclient);
zclient_free(zclient);
zclient = NULL;

View File

@ -586,6 +586,13 @@ main_dispatch_ldpe(struct thread *thread)
fatalx("IMSG_ACL_CHECK imsg with wrong len");
ldp_acl_reply(iev, (struct acl_check *)imsg.data);
break;
case IMSG_LDP_SYNC_IF_STATE_UPDATE:
if (imsg.hdr.len != IMSG_HEADER_SIZE +
sizeof(struct ldp_igp_sync_if_state))
fatalx("IMSG_LDP_SYNC_IF_STATE_UPDATE imsg with wrong len");
ldp_sync_zebra_send_state_update((struct ldp_igp_sync_if_state *)imsg.data);
break;
default:
log_debug("%s: error handling imsg %d", __func__,
imsg.hdr.type);
@ -1148,6 +1155,7 @@ ldp_config_reset_main(struct ldpd_conf *conf)
conf->lhello_interval = DEFAULT_HELLO_INTERVAL;
conf->thello_holdtime = TARGETED_DFLT_HOLDTIME;
conf->thello_interval = DEFAULT_HELLO_INTERVAL;
conf->wait_for_sync_interval = DFLT_WAIT_FOR_SYNC;
conf->trans_pref = DUAL_STACK_LDPOV6;
conf->flags = 0;
}
@ -1278,6 +1286,14 @@ merge_config(struct ldpd_conf *conf, struct ldpd_conf *xconf)
static void
merge_global(struct ldpd_conf *conf, struct ldpd_conf *xconf)
{
/* Removing global LDP config requires resetting LDP IGP Sync FSM */
if ((conf->flags & F_LDPD_ENABLED) &&
(!(xconf->flags & F_LDPD_ENABLED)))
{
if (ldpd_process == PROC_LDP_ENGINE)
ldp_sync_fsm_reset_all();
}
/* change of router-id requires resetting all neighborships */
if (conf->rtr_id.s_addr != xconf->rtr_id.s_addr) {
if (ldpd_process == PROC_LDP_ENGINE) {
@ -1303,6 +1319,7 @@ merge_global(struct ldpd_conf *conf, struct ldpd_conf *xconf)
conf->lhello_interval = xconf->lhello_interval;
conf->thello_holdtime = xconf->thello_holdtime;
conf->thello_interval = xconf->thello_interval;
conf->wait_for_sync_interval = xconf->wait_for_sync_interval;
if (conf->trans_pref != xconf->trans_pref) {
if (ldpd_process == PROC_LDP_ENGINE)

View File

@ -34,6 +34,7 @@
#include "zclient.h"
#include "ldp.h"
#include "lib/ldp_sync.h"
#define CONF_FILE "/etc/ldpd.conf"
#define LDPD_USER "_ldpd"
@ -93,6 +94,7 @@ enum imsg_type {
IMSG_CTL_SHOW_LIB_END,
IMSG_CTL_SHOW_L2VPN_PW,
IMSG_CTL_SHOW_L2VPN_BINDING,
IMSG_CTL_SHOW_LDP_SYNC,
IMSG_CTL_CLEAR_NBR,
IMSG_CTL_FIB_COUPLE,
IMSG_CTL_FIB_DECOUPLE,
@ -153,7 +155,9 @@ enum imsg_type {
IMSG_INIT,
IMSG_PW_UPDATE,
IMSG_FILTER_UPDATE,
IMSG_NBR_SHUTDOWN
IMSG_NBR_SHUTDOWN,
IMSG_LDP_SYNC_IF_STATE_REQUEST,
IMSG_LDP_SYNC_IF_STATE_UPDATE
};
struct ldpd_init {
@ -227,6 +231,34 @@ enum nbr_action {
NBR_ACT_CLOSE_SESSION
};
/* LDP IGP Sync states */
#define LDP_SYNC_STA_UNKNOWN 0x0000
#define LDP_SYNC_STA_NOT_ACH 0x0001
#define LDP_SYNC_STA_ACH 0x0002
/* LDP IGP Sync events */
enum ldp_sync_event {
LDP_SYNC_EVT_NOTHING,
LDP_SYNC_EVT_LDP_SYNC_START,
LDP_SYNC_EVT_LDP_SYNC_COMPLETE,
LDP_SYNC_EVT_CONFIG_LDP_OFF,
LDP_SYNC_EVT_ADJ_DEL,
LDP_SYNC_EVT_ADJ_NEW,
LDP_SYNC_EVT_SESSION_CLOSE,
LDP_SYNC_EVT_CONFIG_LDP_ON,
LDP_SYNC_EVT_IFACE_SHUTDOWN
};
/* LDP IGP Sync actions */
enum ldp_sync_action {
LDP_SYNC_ACT_NOTHING,
LDP_SYNC_ACT_IFACE_START_SYNC,
LDP_SYNC_ACT_LDP_START_SYNC,
LDP_SYNC_ACT_LDP_COMPLETE_SYNC,
LDP_SYNC_ACT_CONFIG_LDP_OFF,
LDP_SYNC_ACT_IFACE_SHUTDOWN
};
/* forward declarations */
RB_HEAD(global_adj_head, adj);
RB_HEAD(nbr_adj_head, adj);
@ -310,6 +342,11 @@ struct iface_af {
uint16_t hello_interval;
};
struct iface_ldp_sync {
int state;
struct thread *wait_for_sync_timer;
};
struct iface {
RB_ENTRY(iface) entry;
char name[IF_NAMESIZE];
@ -320,6 +357,7 @@ struct iface {
int operative;
struct iface_af ipv4;
struct iface_af ipv6;
struct iface_ldp_sync ldp_sync;
QOBJ_FIELDS
};
RB_HEAD(iface_head, iface);
@ -518,6 +556,7 @@ struct ldpd_conf {
uint16_t thello_holdtime;
uint16_t thello_interval;
uint16_t trans_pref;
uint16_t wait_for_sync_interval;
int flags;
QOBJ_FIELDS
};
@ -672,6 +711,16 @@ struct ctl_pw {
uint8_t reason;
};
struct ctl_ldp_sync {
char name[IF_NAMESIZE];
ifindex_t ifindex;
bool in_sync;
bool timer_running;
uint16_t wait_time;
uint16_t wait_time_remaining;
struct in_addr peer_ldp_id;
};
extern struct ldpd_conf *ldpd_conf, *vty_conf;
extern struct ldpd_global global;
extern struct ldpd_init init;
@ -825,6 +874,7 @@ extern char ctl_sock_path[MAXPATHLEN];
/* ldp_zebra.c */
void ldp_zebra_init(struct thread_master *);
void ldp_zebra_destroy(void);
int ldp_sync_zebra_send_state_update(struct ldp_igp_sync_if_state *);
/* compatibility */
#ifndef __OpenBSD__

View File

@ -297,6 +297,7 @@ ldpe_dispatch_main(struct thread *thread)
#endif
int n, shut = 0;
struct ldp_access *laccess;
struct ldp_igp_sync_if_state_req *ldp_sync_if_state_req;
iev->ev_read = NULL;
@ -559,6 +560,15 @@ ldpe_dispatch_main(struct thread *thread)
ldpe_check_filter_af(AF_INET6, &leconf->ipv6,
laccess->name);
break;
case IMSG_LDP_SYNC_IF_STATE_REQUEST:
if (imsg.hdr.len != IMSG_HEADER_SIZE +
sizeof(struct ldp_igp_sync_if_state_req)) {
log_warnx("%s: wrong imsg len", __func__);
break;
}
ldp_sync_if_state_req = imsg.data;
ldp_sync_fsm_state_req(ldp_sync_if_state_req);
break;
default:
log_debug("ldpe_dispatch_main: error handling imsg %d",
imsg.hdr.type);
@ -974,6 +984,20 @@ ldpe_nbr_ctl(struct ctl_conn *c)
imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0);
}
void
ldpe_ldp_sync_ctl(struct ctl_conn *c)
{
struct iface *iface;
struct ctl_ldp_sync *ictl;
RB_FOREACH(iface, iface_head, &leconf->iface_tree) {
ictl = ldp_sync_to_ctl(iface);
imsg_compose_event(&c->iev, IMSG_CTL_SHOW_LDP_SYNC,
0, 0, -1, ictl, sizeof(struct ctl_ldp_sync));
}
imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0);
}
void
mapping_list_add(struct mapping_head *mh, struct map *map)
{

View File

@ -28,6 +28,7 @@
#endif
#include "ldpd.h"
#include "lib/ldp_sync.h"
#define min(x,y) ((x) <= (y) ? (x) : (y))
#define max(x,y) ((x) > (y) ? (x) : (y))
@ -212,6 +213,7 @@ void ldpe_iface_ctl(struct ctl_conn *c, ifindex_t ifidx);
void ldpe_adj_ctl(struct ctl_conn *);
void ldpe_adj_detail_ctl(struct ctl_conn *);
void ldpe_nbr_ctl(struct ctl_conn *);
void ldpe_ldp_sync_ctl(struct ctl_conn *);
void mapping_list_add(struct mapping_head *, struct map *);
void mapping_list_clr(struct mapping_head *);
@ -229,8 +231,17 @@ void ldp_if_update(struct iface *, int);
void if_update_all(int);
uint16_t if_get_hello_holdtime(struct iface_af *);
uint16_t if_get_hello_interval(struct iface_af *);
uint16_t if_get_wait_for_sync_interval(void);
struct ctl_iface *if_to_ctl(struct iface_af *);
in_addr_t if_get_ipv4_addr(struct iface *);
int ldp_sync_fsm_adj_event(struct adj *, enum ldp_sync_event);
int ldp_sync_fsm_nbr_event(struct nbr *, enum ldp_sync_event);
int ldp_sync_fsm_state_req(struct ldp_igp_sync_if_state_req *);
int ldp_sync_fsm(struct iface *, enum ldp_sync_event);
void ldp_sync_fsm_reset_all(void);
const char *ldp_sync_state_name(int);
const char *ldp_sync_event_name(int);
struct ctl_ldp_sync *ldp_sync_to_ctl(struct iface *);
/* adjacency.c */
struct adj *adj_new(struct in_addr, struct hello_source *,

View File

@ -764,6 +764,8 @@ nbr_act_session_operational(struct nbr *nbr)
/* this is necessary to avoid ipc synchronization issues */
nbr_update_peerid(nbr);
ldp_sync_fsm_nbr_event(nbr, LDP_SYNC_EVT_LDP_SYNC_START);
memset(&lde_nbr, 0, sizeof(lde_nbr));
lde_nbr.id = nbr->id;
lde_nbr.v4_enabled = nbr->v4_enabled;

View File

@ -683,6 +683,8 @@ session_close(struct nbr *nbr)
log_debug("%s: closing session with lsr-id %s", __func__,
inet_ntoa(nbr->id));
ldp_sync_fsm_nbr_event(nbr, LDP_SYNC_EVT_SESSION_CLOSE);
tcp_close(nbr->tcp);
nbr_stop_ktimer(nbr);
nbr_stop_ktimeout(nbr);

View File

@ -421,6 +421,11 @@ struct cmd_node {
#define CMD_VNI_RANGE "(1-16777215)"
#define CONF_BACKUP_EXT ".sav"
#define MPLS_LDP_SYNC_STR "Enable MPLS LDP-SYNC\n"
#define NO_MPLS_LDP_SYNC_STR "Disable MPLS LDP-SYNC\n"
#define MPLS_LDP_SYNC_HOLDDOWN_STR \
"Time to wait for LDP-SYNC to occur before restoring if cost\n"
#define NO_MPLS_LDP_SYNC_HOLDDOWN_STR "holddown timer disable\n"
/* Command warnings. */
#define NO_PASSWD_CMD_WARNING \

93
lib/ldp_sync.c Normal file
View File

@ -0,0 +1,93 @@
/*
* ldp_sync.c: LDP-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 "command.h"
#include "memory.h"
#include "prefix.h"
#include "log.h"
#include "thread.h"
#include "stream.h"
#include "zclient.h"
#include "table.h"
#include "vty.h"
#include "ldp_sync.h"
/* Library code */
DEFINE_MTYPE_STATIC(LIB, LDP_SYNC_INFO, "LDP SYNC info")
/*
* ldp_sync_info_create - Allocate the LDP_SYNC information
*/
struct ldp_sync_info *ldp_sync_info_create(void)
{
struct ldp_sync_info *ldp_sync_info;
ldp_sync_info = XCALLOC(MTYPE_LDP_SYNC_INFO,
sizeof(struct ldp_sync_info));
assert(ldp_sync_info);
ldp_sync_info->flags = 0;
ldp_sync_info->enabled = LDP_IGP_SYNC_DEFAULT;
ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED;
ldp_sync_info->holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT;
ldp_sync_info->t_holddown = NULL;
return ldp_sync_info;
}
/*
* ldp_sync_info_free - Free the LDP_SYNC information.
*/
void ldp_sync_info_free(struct ldp_sync_info **ldp_sync_info)
{
if (*ldp_sync_info)
XFREE(MTYPE_LDP_SYNC_INFO, *ldp_sync_info);
}
bool ldp_sync_if_is_enabled(struct ldp_sync_info *ldp_sync_info)
{
/* return true if LDP-SYNC is configured on this interface */
if (ldp_sync_info &&
ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED &&
ldp_sync_info->state == LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP)
return true;
return false;
}
bool ldp_sync_if_down(struct ldp_sync_info *ldp_sync_info)
{
/* Stop LDP-SYNC on this interface:
* if holddown timer is running stop it
* update state
*/
if (ldp_sync_info && ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED) {
if (ldp_sync_info->t_holddown != NULL) {
THREAD_TIMER_OFF(ldp_sync_info->t_holddown);
ldp_sync_info->t_holddown = NULL;
}
if (ldp_sync_info->state == LDP_IGP_SYNC_STATE_REQUIRED_UP)
ldp_sync_info->state =
LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
return true;
}
return false;
}

91
lib/ldp_sync.h Normal file
View File

@ -0,0 +1,91 @@
/*
* Defines and structures common to LDP-Sync for OSPFv2 and OSPFv3 and ISIS
* 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 _LIBLDPSYNC_H
#define _LIBLDPSYNC_H
#ifdef __cplusplus
extern "C" {
#endif
/* LDP-IGP Sync values */
#define LDP_SYNC_FLAG_ENABLE (1 << 0) /* LDP-SYNC enabled */
#define LDP_SYNC_FLAG_HOLDDOWN (1 << 1) /* Holddown timer enabled */
#define LDP_SYNC_FLAG_IF_CONFIG (1 << 2) /* LDP-SYNC enabled on interface */
#define LDP_SYNC_FLAG_SET_METRIC (1 << 3) /* Metric has been set on ISIS intf */
#define LDP_IGP_SYNC_DEFAULT 0
#define LDP_IGP_SYNC_ENABLED 1
#define LDP_IGP_SYNC_STATE_NOT_REQUIRED 0
#define LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP 1
#define LDP_IGP_SYNC_STATE_REQUIRED_UP 2
#define LDP_IGP_SYNC_HOLDDOWN_DEFAULT 0
#define LDP_IGP_SYNC_HELLO_TIMEOUT 1
/* LDP-IGP Sync structures */
struct ldp_sync_info_cmd {
uint16_t flags;
uint16_t holddown; /* timer value */
uint32_t sequence; /* hello sequence number */
struct thread *t_hello; /* hello timer for detecting LDP going down */
};
struct ldp_sync_info {
uint16_t flags; /* indicate if set on interface or globally */
uint8_t enabled; /* enabled */
uint8_t state; /* running state */
uint16_t holddown; /* timer value */
struct thread *t_holddown; /* holddown timer*/
uint32_t metric[2]; /* isis interface metric */
};
/* Prototypes. */
extern struct ldp_sync_info *ldp_sync_info_create(void);
extern bool ldp_sync_if_is_enabled(struct ldp_sync_info *ldp_sync_info);
extern bool ldp_sync_if_down(struct ldp_sync_info *ldp_sync_info);
extern void ldp_sync_info_free(struct ldp_sync_info **ldp_sync_info);
struct ldp_igp_sync_announce {
int proto;
};
struct ldp_igp_sync_if_state {
ifindex_t ifindex;
bool sync_start;
};
struct ldp_igp_sync_if_state_req {
int proto;
ifindex_t ifindex;
char name[INTERFACE_NAMSIZ];
};
struct ldp_igp_sync_hello {
int proto;
unsigned int sequence;
};
#ifdef __cplusplus
}
#endif
#endif /* _LIBLDPSYNC_H */

View File

@ -42,6 +42,7 @@ lib_libfrr_la_SOURCES = \
lib/jhash.c \
lib/json.c \
lib/keychain.c \
lib/ldp_sync.c \
lib/lib_errors.c \
lib/lib_vty.c \
lib/libfrr.c \
@ -198,6 +199,7 @@ pkginclude_HEADERS += \
lib/jhash.h \
lib/json.h \
lib/keychain.h \
lib/ldp_sync.h \
lib/lib_errors.h \
lib/lib_vty.h \
lib/libfrr.h \

View File

@ -955,6 +955,14 @@ enum zapi_opaque_registry {
LINK_STATE_REQUEST = 1,
/* Update containing link-state db info */
LINK_STATE_UPDATE = 2,
/* Request LDP-SYNC state from LDP */
LDP_IGP_SYNC_IF_STATE_REQUEST = 3,
/* Update containing LDP IGP Sync State info */
LDP_IGP_SYNC_IF_STATE_UPDATE = 4,
/* Announce that LDP is up */
LDP_IGP_SYNC_ANNOUNCE_UPDATE = 5,
/* Heartbeat indicating that LDP is running */
LDP_IGP_SYNC_HELLO_UPDATE = 6,
};
/* Send the hello message.

View File

@ -54,6 +54,7 @@ unsigned long conf_debug_ospf_te = 0;
unsigned long conf_debug_ospf_ext = 0;
unsigned long conf_debug_ospf_sr = 0;
unsigned long conf_debug_ospf_defaultinfo = 0;
unsigned long conf_debug_ospf_ldp_sync = 0;
/* Enable debug option variables -- valid only session. */
unsigned long term_debug_ospf_packet[5] = {0, 0, 0, 0, 0};
@ -67,6 +68,7 @@ unsigned long term_debug_ospf_te = 0;
unsigned long term_debug_ospf_ext = 0;
unsigned long term_debug_ospf_sr = 0;
unsigned long term_debug_ospf_defaultinfo;
unsigned long term_debug_ospf_ldp_sync;
const char *ospf_redist_string(unsigned int route_type)
{
@ -1476,6 +1478,32 @@ DEFUN (no_debug_ospf_default_info,
return CMD_SUCCESS;
}
DEFUN(debug_ospf_ldp_sync,
debug_ospf_ldp_sync_cmd,
"debug ospf ldp-sync",
DEBUG_STR OSPF_STR
"OSPF LDP-Sync information\n")
{
if (vty->node == CONFIG_NODE)
CONF_DEBUG_ON(ldp_sync, LDP_SYNC);
TERM_DEBUG_ON(ldp_sync, LDP_SYNC);
return CMD_SUCCESS;
}
DEFUN(no_debug_ospf_ldp_sync,
no_debug_ospf_ldp_sync_cmd,
"no debug ospf ldp-sync",
NO_STR
DEBUG_STR
OSPF_STR
"OSPF LDP-Sync information\n")
{
if (vty->node == CONFIG_NODE)
CONF_DEBUG_OFF(ldp_sync, LDP_SYNC);
TERM_DEBUG_OFF(ldp_sync, LDP_SYNC);
return CMD_SUCCESS;
}
DEFUN (no_debug_ospf,
no_debug_ospf_cmd,
"no debug ospf",
@ -1505,6 +1533,7 @@ DEFUN (no_debug_ospf,
DEBUG_OFF(zebra, ZEBRA_INTERFACE);
DEBUG_OFF(zebra, ZEBRA_REDISTRIBUTE);
DEBUG_OFF(defaultinfo, DEFAULTINFO);
DEBUG_OFF(ldp_sync, LDP_SYNC);
for (i = 0; i < 5; i++)
DEBUG_PACKET_OFF(i, flag);
@ -1532,6 +1561,7 @@ DEFUN (no_debug_ospf,
TERM_DEBUG_OFF(zebra, ZEBRA_INTERFACE);
TERM_DEBUG_OFF(zebra, ZEBRA_REDISTRIBUTE);
TERM_DEBUG_OFF(defaultinfo, DEFAULTINFO);
TERM_DEBUG_OFF(ldp_sync, LDP_SYNC);
return CMD_SUCCESS;
}
@ -1633,6 +1663,10 @@ static int show_debugging_ospf_common(struct vty *vty, struct ospf *ospf)
if (IS_DEBUG_OSPF(nssa, NSSA) == OSPF_DEBUG_NSSA)
vty_out(vty, " OSPF NSSA debugging is on\n");
/* Show debug status for LDP-SYNC. */
if (IS_DEBUG_OSPF(ldp_sync, LDP_SYNC) == OSPF_DEBUG_LDP_SYNC)
vty_out(vty, " OSPF ldp-sync debugging is on\n");
vty_out(vty, "\n");
return CMD_SUCCESS;
@ -1814,6 +1848,11 @@ static int config_write_debug(struct vty *vty)
write = 1;
}
/* debug ospf ldp-sync */
if (IS_CONF_DEBUG_OSPF(ldp_sync, LDP_SYNC) == OSPF_DEBUG_LDP_SYNC) {
vty_out(vty, "debug ospf%s ldp-sync\n", str);
write = 1;
}
return write;
}
@ -1832,6 +1871,7 @@ void ospf_debug_init(void)
install_element(ENABLE_NODE, &debug_ospf_te_cmd);
install_element(ENABLE_NODE, &debug_ospf_sr_cmd);
install_element(ENABLE_NODE, &debug_ospf_default_info_cmd);
install_element(ENABLE_NODE, &debug_ospf_ldp_sync_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_ism_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_nsm_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_lsa_cmd);
@ -1841,6 +1881,7 @@ void ospf_debug_init(void)
install_element(ENABLE_NODE, &no_debug_ospf_te_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_sr_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_default_info_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_ldp_sync_cmd);
install_element(ENABLE_NODE, &show_debugging_ospf_instance_cmd);
install_element(ENABLE_NODE, &debug_ospf_packet_cmd);
@ -1871,6 +1912,7 @@ void ospf_debug_init(void)
install_element(CONFIG_NODE, &debug_ospf_te_cmd);
install_element(CONFIG_NODE, &debug_ospf_sr_cmd);
install_element(CONFIG_NODE, &debug_ospf_default_info_cmd);
install_element(CONFIG_NODE, &debug_ospf_ldp_sync_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_nsm_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_lsa_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_zebra_cmd);
@ -1879,6 +1921,7 @@ void ospf_debug_init(void)
install_element(CONFIG_NODE, &no_debug_ospf_te_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_sr_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_default_info_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_ldp_sync_cmd);
install_element(CONFIG_NODE, &debug_ospf_instance_nsm_cmd);
install_element(CONFIG_NODE, &debug_ospf_instance_lsa_cmd);

View File

@ -60,6 +60,7 @@
#define OSPF_DEBUG_EXT 0x08
#define OSPF_DEBUG_SR 0x10
#define OSPF_DEBUG_DEFAULTINFO 0x20
#define OSPF_DEBUG_LDP_SYNC 0x40
/* Macro for setting debug option. */
#define CONF_DEBUG_PACKET_ON(a, b) conf_debug_ospf_packet[a] |= (b)
@ -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[];

View File

@ -32,6 +32,7 @@
#include "log.h"
#include "zclient.h"
#include "bfd.h"
#include "ldp_sync.h"
#include "ospfd/ospfd.h"
#include "ospfd/ospf_spf.h"
@ -46,6 +47,7 @@
#include "ospfd/ospf_abr.h"
#include "ospfd/ospf_network.h"
#include "ospfd/ospf_dump.h"
#include "ospfd/ospf_ldp_sync.h"
DEFINE_QOBJ_TYPE(ospf_interface)
DEFINE_HOOK(ospf_vl_add, (struct ospf_vl_data * vd), (vd))
@ -81,6 +83,12 @@ int ospf_if_get_output_cost(struct ospf_interface *oi)
uint32_t cost;
uint32_t bw, refbw;
/* if LDP-IGP Sync is running on interface set cost so interface
* is used only as last resort
*/
if (ldp_sync_if_is_enabled(IF_DEF_PARAMS(oi->ifp)->ldp_sync_info))
return (LDP_OSPF_LSINFINITY);
/* ifp speed and bw can be 0 in some platforms, use ospf default bw
if bw is configured under interface it would be used.
*/
@ -539,6 +547,7 @@ void ospf_del_if_params(struct ospf_if_params *oip)
{
list_delete(&oip->auth_crypt);
bfd_info_free(&(oip->bfd_info));
ldp_sync_info_free(&(oip->ldp_sync_info));
XFREE(MTYPE_OSPF_IF_PARAMS, oip);
}

View File

@ -104,6 +104,9 @@ struct ospf_if_params {
/* BFD configuration */
struct bfd_info *bfd_info;
/* MPLS LDP-IGP Sync configuration */
struct ldp_sync_info *ldp_sync_info;
};
enum { MEMBER_ALLROUTERS = 0,

1142
ospfd/ospf_ldp_sync.c Normal file

File diff suppressed because it is too large Load Diff

56
ospfd/ospf_ldp_sync.h Normal file
View File

@ -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 */

View File

@ -54,6 +54,7 @@
#include "ospfd/ospf_vty.h"
#include "ospfd/ospf_bfd.h"
#include "ospfd/ospf_errors.h"
#include "ospfd/ospf_ldp_sync.h"
/* ospfd privileges */
zebra_capabilities_t _caps_p[] = {ZCAP_NET_RAW, ZCAP_BIND, ZCAP_NET_ADMIN,
@ -217,6 +218,9 @@ int main(int argc, char **argv)
/* OSPF BFD init */
ospf_bfd_init();
/* OSPF LDP IGP Sync init */
ospf_ldp_sync_init();
ospf_route_map_init();
ospf_opaque_init();

View File

@ -52,6 +52,7 @@
#include "ospfd/ospf_vty.h"
#include "ospfd/ospf_dump.h"
#include "ospfd/ospf_bfd.h"
#include "ospfd/ospf_ldp_sync.h"
FRR_CFG_DEFAULT_BOOL(OSPF_LOG_ADJACENCY_CHANGES,
{ .val_bool = true, .match_profile = "datacenter", },
@ -3222,6 +3223,10 @@ static int show_ip_ospf_common(struct vty *vty, struct ospf *ospf,
vty_out(vty, " Adjacency changes are logged\n");
}
}
/* show LDP-Sync status */
ospf_ldp_sync_show_info(vty, ospf, json_vrf, json ? 1 : 0);
/* Show each area status. */
for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area))
show_ip_ospf_area(vty, area, json_areas, json ? 1 : 0);
@ -9975,6 +9980,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)
@ -10498,6 +10506,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;
}

View File

@ -51,6 +51,7 @@
#include "ospfd/ospf_zebra.h"
#include "ospfd/ospf_te.h"
#include "ospfd/ospf_sr.h"
#include "ospfd/ospf_ldp_sync.h"
DEFINE_MTYPE_STATIC(OSPFD, OSPF_EXTERNAL, "OSPF External route table")
DEFINE_MTYPE_STATIC(OSPFD, OSPF_REDISTRIBUTE, "OSPF Redistriute")
@ -1833,6 +1834,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. */
@ -1866,6 +1906,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)

View File

@ -39,6 +39,7 @@
#include "libfrr.h"
#include "defaults.h"
#include "lib_errors.h"
#include "ldp_sync.h"
#include "ospfd/ospfd.h"
#include "ospfd/ospf_network.h"
@ -57,6 +58,7 @@
#include "ospfd/ospf_abr.h"
#include "ospfd/ospf_flood.h"
#include "ospfd/ospf_ase.h"
#include "ospfd/ospf_ldp_sync.h"
DEFINE_QOBJ_TYPE(ospf)
@ -619,6 +621,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;
@ -948,6 +954,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.

View File

@ -25,6 +25,7 @@
#include <zebra.h>
#include "qobj.h"
#include "libospf.h"
#include "ldp_sync.h"
#include "filter.h"
#include "log.h"
@ -320,6 +321,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)

View File

@ -9,6 +9,7 @@ dist_examples_DATA += ospfd/ospfd.conf.sample
vtysh_scan += \
ospfd/ospf_bfd.c \
ospfd/ospf_dump.c \
ospfd/ospf_ldp_sync.c \
ospfd/ospf_opaque.c \
ospfd/ospf_ri.c \
ospfd/ospf_routemap.c \
@ -37,6 +38,7 @@ ospfd_libfrrospf_a_SOURCES = \
ospfd/ospf_ia.c \
ospfd/ospf_interface.c \
ospfd/ospf_ism.c \
ospfd/ospf_ldp_sync.c \
ospfd/ospf_lsa.c \
ospfd/ospf_lsdb.c \
ospfd/ospf_memory.c \
@ -74,6 +76,7 @@ endif
clippy_scan += \
ospfd/ospf_vty.c \
ospfd/ospf_ldp_sync.c \
# end
noinst_HEADERS += \
@ -86,6 +89,7 @@ noinst_HEADERS += \
ospfd/ospf_flood.h \
ospfd/ospf_ia.h \
ospfd/ospf_interface.h \
ospfd/ospf_ldp_sync.h \
ospfd/ospf_memory.h \
ospfd/ospf_neighbor.h \
ospfd/ospf_network.h \

View File

@ -0,0 +1,12 @@
log file zebra.log
!
hostname ce1
!
interface ce1-eth0
ip address 172.16.1.1/24
no link-detect
!
ip forwarding
!
line vty
!

View File

@ -0,0 +1,12 @@
log file zebra.log
!
hostname ce2
!
interface ce2-eth0
ip address 172.16.1.2/24
no link-detect
!
ip forwarding
!
line vty
!

View File

@ -0,0 +1,12 @@
log file zebra.log
!
hostname ce3
!
interface ce3-eth0
ip address 172.16.1.3/24
no link-detect
!
ip forwarding
!
line vty
!

View File

@ -0,0 +1,26 @@
hostname r1
log file isisd.log
debug isis adj-packets
debug isis events
debug isis update-packets
debug isis ldp-sync
!
router isis 1
net 10.0000.0000.0000.0000.0000.0000.0000.0000.0001.00
metric-style wide
redistribute ipv4 connected level-1
redistribute ipv6 connected level-1
mpls ldp-sync
!
interface r1-eth1
ip router isis 1
ipv6 router isis 1
isis network point-to-point
isis circuit-type level-1
!
interface r1-eth2
ip router isis 1
ipv6 router isis 1
isis network point-to-point
isis circuit-type level-1
!

View File

@ -0,0 +1,33 @@
hostname r1
log file ldpd.log
!
debug mpls ldp zebra
debug mpls ldp event
debug mpls ldp errors
debug mpls ldp sync
!
mpls ldp
router-id 1.1.1.1
!
address-family ipv4
discovery transport-address 1.1.1.1
label local allocate host-routes
!
ttl-security disable
!
interface r1-eth1
!
interface r1-eth2
!
!
!
l2vpn CUST_A type vpls
member interface r1-eth0
!
member pseudowire r1-mpw0
neighbor lsr-id 2.2.2.2
pw-id 100
!
!
line vty
!

View File

@ -0,0 +1,143 @@
{
"1.1.1.1\/32":[
{
"prefix":"1.1.1.1\/32",
"protocol":"connected",
"selected":true,
"nexthops":[
{
"fib":true,
"directlyConnected":true,
"interfaceIndex":1,
"interfaceName":"lo",
"active":true
}
]
}
],
"2.2.2.2\/32":[
{
"prefix":"2.2.2.2\/32",
"protocol":"isis",
"selected":true,
"distance":115,
"metric":10,
"nexthops":[
{
"fib":true,
"ip":"10.0.1.2",
"afi":"ipv4",
"interfaceIndex":3,
"interfaceName":"r1-eth1",
"active":true
}
]
}
],
"3.3.3.3\/32":[
{
"prefix":"3.3.3.3\/32",
"protocol":"isis",
"selected":true,
"distance":115,
"metric":10,
"nexthops":[
{
"fib":true,
"ip":"10.0.2.3",
"afi":"ipv4",
"interfaceIndex":4,
"interfaceName":"r1-eth2",
"active":true
}
]
}
],
"10.0.1.0\/24":[
{
"prefix":"10.0.1.0\/24",
"protocol":"isis",
"distance":115,
"metric":10,
"nexthops":[
{
"ip":"10.0.1.2",
"afi":"ipv4",
"interfaceIndex":3,
"interfaceName":"r1-eth1"
}
]
},
{
"prefix":"10.0.1.0\/24",
"protocol":"connected",
"selected":true,
"nexthops":[
{
"fib":true,
"directlyConnected":true,
"interfaceIndex":3,
"interfaceName":"r1-eth1",
"active":true
}
]
}
],
"10.0.2.0\/24":[
{
"prefix":"10.0.2.0\/24",
"protocol":"isis",
"distance":115,
"metric":10,
"nexthops":[
{
"ip":"10.0.2.3",
"afi":"ipv4",
"interfaceIndex":4,
"interfaceName":"r1-eth2"
}
]
},
{
"prefix":"10.0.2.0\/24",
"protocol":"connected",
"selected":true,
"nexthops":[
{
"fib":true,
"directlyConnected":true,
"interfaceIndex":4,
"interfaceName":"r1-eth2",
"active":true
}
]
}
],
"10.0.3.0\/24":[
{
"prefix":"10.0.3.0\/24",
"protocol":"isis",
"selected":true,
"distance":115,
"metric":10,
"nexthops":[
{
"fib":true,
"ip":"10.0.1.2",
"afi":"ipv4",
"interfaceIndex":3,
"interfaceName":"r1-eth1",
"active":true
},
{
"fib":true,
"ip":"10.0.2.3",
"afi":"ipv4",
"interfaceIndex":4,
"interfaceName":"r1-eth2",
"active":true
}
]
}
]
}

View File

@ -0,0 +1,16 @@
{
"1": {
"r1-eth1": [
{
"level": "Level-1",
"metric": "10"
}
],
"r1-eth2": [
{
"level": "Level-1",
"metric": "10"
}
]
}
}

View File

@ -0,0 +1,16 @@
{
"1": {
"r1-eth1": [
{
"level": "Level-1",
"metric": "16777214"
}
],
"r1-eth2": [
{
"level": "Level-1",
"metric": "10"
}
]
}
}

View File

@ -0,0 +1,16 @@
{
"1": {
"r1-eth1": [
{
"level": "Level-1",
"metric": "16777214"
}
],
"r1-eth2": [
{
"level": "Level-1",
"metric": "10"
}
]
}
}

View File

@ -0,0 +1,13 @@
{
"r1-eth1":{
"ldpIgpSyncEnabled":true,
"holdDownTimeInSec":0,
"ldpIgpSyncState":"Sync achieved"
},
"r1-eth2":{
"ldpIgpSyncEnabled":true,
"holdDownTimeInSec":0,
"ldpIgpSyncState":"Sync achieved"
}
}

View File

@ -0,0 +1,13 @@
{
"r1-eth1":{
"ldpIgpSyncEnabled":true,
"holdDownTimeInSec":0,
"ldpIgpSyncState":"Sync not achieved"
},
"r1-eth2":{
"ldpIgpSyncEnabled":true,
"holdDownTimeInSec":0,
"ldpIgpSyncState":"Sync achieved"
}
}

View File

@ -0,0 +1,13 @@
{
"r1-eth1":{
"ldpIgpSyncEnabled":true,
"holdDownTimeInSec":0,
"ldpIgpSyncState":"Sync not achieved"
},
"r1-eth2":{
"ldpIgpSyncEnabled":true,
"holdDownTimeInSec":0,
"ldpIgpSyncState":"Sync achieved"
}
}

View File

@ -0,0 +1,16 @@
{
"2.2.2.2: 100":{
"destination":"2.2.2.2",
"vcId":100,
"localLabel":16,
"localControlWord":1,
"localVcType":"Ethernet",
"localGroupID":0,
"localIfMtu":1500,
"remoteLabel":16,
"remoteControlWord":1,
"remoteVcType":"Ethernet",
"remoteGroupID":0,
"remoteIfMtu":1500
}
}

View File

@ -0,0 +1,8 @@
{
"r1-mpw0":{
"peerId":"2.2.2.2",
"vcId":100,
"VpnName":"CUST_A",
"status":"up"
}
}

View File

@ -0,0 +1,44 @@
{
"bindings":[
{
"addressFamily":"ipv4",
"prefix":"1.1.1.1/32",
"neighborId":"2.2.2.2",
"localLabel":"imp-null",
"inUse":0
},
{
"addressFamily":"ipv4",
"prefix":"1.1.1.1/32",
"neighborId":"3.3.3.3",
"localLabel":"imp-null",
"inUse":0
},
{
"addressFamily":"ipv4",
"prefix":"2.2.2.2/32",
"neighborId":"2.2.2.2",
"remoteLabel":"imp-null",
"inUse":1
},
{
"addressFamily":"ipv4",
"prefix":"2.2.2.2/32",
"neighborId":"3.3.3.3",
"inUse":0
},
{
"addressFamily":"ipv4",
"prefix":"3.3.3.3/32",
"neighborId":"2.2.2.2",
"inUse":0
},
{
"addressFamily":"ipv4",
"prefix":"3.3.3.3/32",
"neighborId":"3.3.3.3",
"remoteLabel":"imp-null",
"inUse":1
}
]
}

View File

@ -0,0 +1,25 @@
{
"adjacencies":[
{
"addressFamily":"ipv4",
"neighborId":"2.2.2.2",
"type":"link",
"interface":"r1-eth1",
"helloHoldtime":15
},
{
"addressFamily":"ipv4",
"neighborId":"2.2.2.2",
"type":"targeted",
"peer":"2.2.2.2",
"helloHoldtime":45
},
{
"addressFamily":"ipv4",
"neighborId":"3.3.3.3",
"type":"link",
"interface":"r1-eth2",
"helloHoldtime":15
}
]
}

View File

@ -0,0 +1,16 @@
{
"r1-eth1":{
"state":"labelExchangeComplete",
"waitTime":10,
"waitTimeRemaining":0,
"timerRunning":false,
"peerLdpId":"2.2.2.2"
},
"r1-eth2":{
"state":"labelExchangeComplete",
"waitTime":10,
"waitTimeRemaining":0,
"timerRunning":false,
"peerLdpId":"3.3.3.3"
}
}

View File

@ -0,0 +1,16 @@
{
"r1-eth1":{
"state":"labelExchangeNotComplete",
"waitTime":10,
"waitTimeRemaining":0,
"timerRunning":false,
"peerLdpId":""
},
"r1-eth2":{
"state":"labelExchangeComplete",
"waitTime":10,
"waitTimeRemaining":0,
"timerRunning":false,
"peerLdpId":"3.3.3.3"
}
}

View File

@ -0,0 +1,16 @@
{
"neighbors":[
{
"addressFamily":"ipv4",
"neighborId":"2.2.2.2",
"state":"OPERATIONAL",
"transportAddress":"2.2.2.2"
},
{
"addressFamily":"ipv4",
"neighborId":"3.3.3.3",
"state":"OPERATIONAL",
"transportAddress":"3.3.3.3"
}
]
}

View File

@ -0,0 +1,42 @@
{
"frr-interface:lib": {
"interface": [
{
"name": "r1-eth1",
"vrf": "default",
"state": {
"frr-isisd:isis": {
"adjacencies": {
"adjacency": [
{
"neighbor-sys-type": "level-1",
"neighbor-sysid": "0000.0000.0002",
"neighbor-extended-circuit-id": 0,
"state": "up"
}
]
}
}
}
},
{
"name": "r1-eth2",
"vrf": "default",
"state": {
"frr-isisd:isis": {
"adjacencies": {
"adjacency": [
{
"neighbor-sys-type": "level-1",
"neighbor-sysid": "0000.0000.0003",
"neighbor-extended-circuit-id": 0,
"state": "up"
}
]
}
}
}
}
]
}
}

View File

@ -0,0 +1,29 @@
log file zebra.log
!
hostname r1
!
debug zebra kernel
debug zebra rib detailed
debug zebra dplane detailed
debug zebra nht
debug zebra pseudowires
debug zebra mpls
!
interface lo
ip address 1.1.1.1/32
!
interface r1-eth0
description to s1
!
interface r1-eth1
description to s4
ip address 10.0.1.1/24
!
interface r1-eth2
description to s5
ip address 10.0.2.1/24
!
ip forwarding
!
line vty
!

View File

@ -0,0 +1,27 @@
hostname r2
log file isisd.log
debug isis adj-packets
debug isis events
debug isis update-packets
debug isis ldp-sync
!
router isis 1
net 10.0000.0000.0000.0000.0000.0000.0000.0000.0002.00
metric-style wide
redistribute ipv4 connected level-1
redistribute ipv6 connected level-1
mpls ldp-sync
!
interface r2-eth1
ip router isis 1
ipv6 router isis 1
isis network point-to-point
isis circuit-type level-1
!
interface r2-eth2
ip router isis 1
ipv6 router isis 1
isis network point-to-point
isis circuit-type level-1
no isis mpls ldp-sync
!

View File

@ -0,0 +1,33 @@
hostname r2
log file ldpd.log
!
debug mpls ldp zebra
debug mpls ldp event
debug mpls ldp errors
debug mpls ldp sync
!
mpls ldp
router-id 2.2.2.2
!
address-family ipv4
discovery transport-address 2.2.2.2
label local allocate host-routes
!
ttl-security disable
!
interface r2-eth1
!
interface r2-eth2
!
!
!
l2vpn CUST_A type vpls
member interface r2-eth0
!
member pseudowire r2-mpw0
neighbor lsr-id 1.1.1.1
pw-id 100
!
!
line vty
!

View File

@ -0,0 +1,19 @@
hostname r2
log file ospfd.log
debug ospf zebra interface
debug ospf ldp-sync
!
router ospf
router-id 2.2.2.2
network 0.0.0.0/0 area 0
mpls ldp-sync
mpls ldp-sync holddown 50
!
interface r2-eth1
ip ospf network point-to-point
ip ospf mpls ldp-sync holddown 300
!
interface r2-eth2
ip ospf network point-to-point
no ip ospf mpls ldp-sync
!

View File

@ -0,0 +1,143 @@
{
"1.1.1.1\/32":[
{
"prefix":"1.1.1.1\/32",
"protocol":"isis",
"selected":true,
"distance":115,
"metric":10,
"nexthops":[
{
"fib":true,
"ip":"10.0.1.1",
"afi":"ipv4",
"interfaceIndex":3,
"interfaceName":"r2-eth1",
"active":true
}
]
}
],
"2.2.2.2\/32":[
{
"prefix":"2.2.2.2\/32",
"protocol":"connected",
"selected":true,
"nexthops":[
{
"fib":true,
"directlyConnected":true,
"interfaceIndex":1,
"interfaceName":"lo",
"active":true
}
]
}
],
"3.3.3.3\/32":[
{
"prefix":"3.3.3.3\/32",
"protocol":"isis",
"selected":true,
"distance":115,
"metric":10,
"nexthops":[
{
"fib":true,
"ip":"10.0.3.3",
"afi":"ipv4",
"interfaceIndex":4,
"interfaceName":"r2-eth2",
"active":true
}
]
}
],
"10.0.1.0\/24":[
{
"prefix":"10.0.1.0\/24",
"protocol":"isis",
"distance":115,
"metric":10,
"nexthops":[
{
"ip":"10.0.1.1",
"afi":"ipv4",
"interfaceIndex":3,
"interfaceName":"r2-eth1"
}
]
},
{
"prefix":"10.0.1.0\/24",
"protocol":"connected",
"selected":true,
"nexthops":[
{
"fib":true,
"directlyConnected":true,
"interfaceIndex":3,
"interfaceName":"r2-eth1",
"active":true
}
]
}
],
"10.0.2.0\/24":[
{
"prefix":"10.0.2.0\/24",
"protocol":"isis",
"selected":true,
"distance":115,
"metric":10,
"nexthops":[
{
"fib":true,
"ip":"10.0.1.1",
"afi":"ipv4",
"interfaceIndex":3,
"interfaceName":"r2-eth1",
"active":true
},
{
"fib":true,
"ip":"10.0.3.3",
"afi":"ipv4",
"interfaceIndex":4,
"interfaceName":"r2-eth2",
"active":true
}
]
}
],
"10.0.3.0\/24":[
{
"prefix":"10.0.3.0\/24",
"protocol":"isis",
"distance":115,
"metric":10,
"nexthops":[
{
"ip":"10.0.3.3",
"afi":"ipv4",
"interfaceIndex":4,
"interfaceName":"r2-eth2"
}
]
},
{
"prefix":"10.0.3.0\/24",
"protocol":"connected",
"selected":true,
"nexthops":[
{
"fib":true,
"directlyConnected":true,
"interfaceIndex":4,
"interfaceName":"r2-eth2",
"active":true
}
]
}
]
}

View File

@ -0,0 +1,16 @@
{
"1": {
"r2-eth1": [
{
"level": "Level-1",
"metric": "10"
}
],
"r2-eth2": [
{
"level": "Level-1",
"metric": "10"
}
]
}
}

View File

@ -0,0 +1,16 @@
{
"1": {
"r2-eth1": [
{
"level": "Level-1",
"metric": "16777214"
}
],
"r2-eth2": [
{
"level": "Level-1",
"metric": "10"
}
]
}
}

View File

@ -0,0 +1,16 @@
{
"1": {
"r2-eth1": [
{
"level": "Level-1",
"metric": "16777214"
}
],
"r2-eth2": [
{
"level": "Level-1",
"metric": "10"
}
]
}
}

View File

@ -0,0 +1,13 @@
{
"r2-eth1":{
"ldpIgpSyncEnabled":true,
"holdDownTimeInSec":0,
"ldpIgpSyncState":"Sync achieved"
},
"r2-eth2":{
"ldpIgpSyncEnabled":false,
"holdDownTimeInSec":0,
"ldpIgpSyncState":"Sync not required"
}
}

View File

@ -0,0 +1,13 @@
{
"r2-eth1":{
"ldpIgpSyncEnabled":true,
"holdDownTimeInSec":0,
"ldpIgpSyncState":"Sync not achieved"
},
"r2-eth2":{
"ldpIgpSyncEnabled":false,
"holdDownTimeInSec":0,
"ldpIgpSyncState":"Sync not required"
}
}

View File

@ -0,0 +1,13 @@
{
"r2-eth1":{
"ldpIgpSyncEnabled":true,
"holdDownTimeInSec":0,
"ldpIgpSyncState":"Sync not achieved"
},
"r2-eth2":{
"ldpIgpSyncEnabled":false,
"holdDownTimeInSec":0,
"ldpIgpSyncState":"Sync not required"
}
}

View File

@ -0,0 +1,16 @@
{
"1.1.1.1: 100":{
"destination":"1.1.1.1",
"vcId":100,
"localLabel":16,
"localControlWord":1,
"localVcType":"Ethernet",
"localGroupID":0,
"localIfMtu":1500,
"remoteLabel":16,
"remoteControlWord":1,
"remoteVcType":"Ethernet",
"remoteGroupID":0,
"remoteIfMtu":1500
}
}

View File

@ -0,0 +1,8 @@
{
"r2-mpw0":{
"peerId":"1.1.1.1",
"vcId":100,
"VpnName":"CUST_A",
"status":"up"
}
}

View File

@ -0,0 +1,44 @@
{
"bindings":[
{
"addressFamily":"ipv4",
"prefix":"1.1.1.1/32",
"neighborId":"1.1.1.1",
"remoteLabel":"imp-null",
"inUse":1
},
{
"addressFamily":"ipv4",
"prefix":"1.1.1.1/32",
"neighborId":"3.3.3.3",
"inUse":0
},
{
"addressFamily":"ipv4",
"prefix":"2.2.2.2/32",
"neighborId":"1.1.1.1",
"localLabel":"imp-null",
"inUse":0
},
{
"addressFamily":"ipv4",
"prefix":"2.2.2.2/32",
"neighborId":"3.3.3.3",
"localLabel":"imp-null",
"inUse":0
},
{
"addressFamily":"ipv4",
"prefix":"3.3.3.3/32",
"neighborId":"1.1.1.1",
"inUse":0
},
{
"addressFamily":"ipv4",
"prefix":"3.3.3.3/32",
"neighborId":"3.3.3.3",
"remoteLabel":"imp-null",
"inUse":1
}
]
}

View File

@ -0,0 +1,25 @@
{
"adjacencies":[
{
"addressFamily":"ipv4",
"neighborId":"1.1.1.1",
"type":"link",
"interface":"r2-eth1",
"helloHoldtime":15
},
{
"addressFamily":"ipv4",
"neighborId":"1.1.1.1",
"type":"targeted",
"peer":"1.1.1.1",
"helloHoldtime":45
},
{
"addressFamily":"ipv4",
"neighborId":"3.3.3.3",
"type":"link",
"interface":"r2-eth2",
"helloHoldtime":15
}
]
}

View File

@ -0,0 +1,16 @@
{
"r2-eth1":{
"state":"labelExchangeComplete",
"waitTime":10,
"waitTimeRemaining":0,
"timerRunning":false,
"peerLdpId":"1.1.1.1"
},
"r2-eth2":{
"state":"labelExchangeComplete",
"waitTime":10,
"waitTimeRemaining":0,
"timerRunning":false,
"peerLdpId":"3.3.3.3"
}
}

View File

@ -0,0 +1,16 @@
{
"r2-eth1":{
"state":"labelExchangeNotComplete",
"waitTime":10,
"waitTimeRemaining":0,
"timerRunning":false,
"peerLdpId":""
},
"r2-eth2":{
"state":"labelExchangeComplete",
"waitTime":10,
"waitTimeRemaining":0,
"timerRunning":false,
"peerLdpId":"3.3.3.3"
}
}

View File

@ -0,0 +1,16 @@
{
"r2-eth1":{
"state":"labelExchangeComplete",
"waitTime":10,
"waitTimeRemaining":0,
"timerRunning":false,
"peerLdpId":"1.1.1.1"
},
"r2-eth2":{
"state":"labelExchangeComplete",
"waitTime":10,
"waitTimeRemaining":0,
"timerRunning":false,
"peerLdpId":"3.3.3.3"
}
}

View File

@ -0,0 +1,16 @@
{
"neighbors":[
{
"addressFamily":"ipv4",
"neighborId":"1.1.1.1",
"state":"OPERATIONAL",
"transportAddress":"1.1.1.1"
},
{
"addressFamily":"ipv4",
"neighborId":"3.3.3.3",
"state":"OPERATIONAL",
"transportAddress":"3.3.3.3"
}
]
}

View File

@ -0,0 +1,42 @@
{
"frr-interface:lib": {
"interface": [
{
"name": "r2-eth1",
"vrf": "default",
"state": {
"frr-isisd:isis": {
"adjacencies": {
"adjacency": [
{
"neighbor-sys-type": "level-1",
"neighbor-sysid": "0000.0000.0001",
"neighbor-extended-circuit-id": 0,
"state": "up"
}
]
}
}
}
},
{
"name": "r2-eth2",
"vrf": "default",
"state": {
"frr-isisd:isis": {
"adjacencies": {
"adjacency": [
{
"neighbor-sys-type": "level-1",
"neighbor-sysid": "0000.0000.0003",
"neighbor-extended-circuit-id": 0,
"state": "up"
}
]
}
}
}
}
]
}
}

View File

@ -0,0 +1,28 @@
log file zebra.log
!
hostname r2
!
debug zebra rib detailed
debug zebra dplane detailed
debug zebra kernel
debug zebra nht
debug zebra pseudowires
!
interface lo
ip address 2.2.2.2/32
!
interface r2-eth0
description to s2
!
interface r2-eth1
description to s4
ip address 10.0.1.2/24
!
interface r2-eth2
description to s6
ip address 10.0.3.2/24
!
ip forwarding
!
line vty
!

View File

@ -0,0 +1,28 @@
hostname r3
log file isisd.log
debug isis adj-packets
debug isis events
debug isis update-packets
debug isis ldp-sync
!
router isis 1
net 10.0000.0000.0000.0000.0000.0000.0000.0000.0003.00
metric-style wide
redistribute ipv4 connected level-1
redistribute ipv6 connected level-1
mpls ldp-sync
mpls ldp-sync holddown 50
!
interface r3-eth1
ip router isis 1
ipv6 router isis 1
isis network point-to-point
isis circuit-type level-1
no isis mpls ldp-sync
!
interface r3-eth2
ip router isis 1
ipv6 router isis 1
isis network point-to-point
isis circuit-type level-1
!

View File

@ -0,0 +1,25 @@
hostname r3
log file ldpd.log
!
debug mpls ldp zebra
debug mpls ldp event
debug mpls ldp errors
debug mpls ldp sync
!
mpls ldp
router-id 3.3.3.3
!
address-family ipv4
discovery transport-address 3.3.3.3
label local allocate host-routes
!
ttl-security disable
!
interface r3-eth1
!
interface r3-eth2
!
!
!
line vty
!

View File

@ -0,0 +1,143 @@
{
"1.1.1.1\/32":[
{
"prefix":"1.1.1.1\/32",
"protocol":"isis",
"selected":true,
"distance":115,
"metric":10,
"nexthops":[
{
"fib":true,
"ip":"10.0.2.1",
"afi":"ipv4",
"interfaceIndex":3,
"interfaceName":"r3-eth1",
"active":true
}
]
}
],
"2.2.2.2\/32":[
{
"prefix":"2.2.2.2\/32",
"protocol":"isis",
"selected":true,
"distance":115,
"metric":10,
"nexthops":[
{
"fib":true,
"ip":"10.0.3.2",
"afi":"ipv4",
"interfaceIndex":4,
"interfaceName":"r3-eth2",
"active":true
}
]
}
],
"3.3.3.3\/32":[
{
"prefix":"3.3.3.3\/32",
"protocol":"connected",
"selected":true,
"nexthops":[
{
"fib":true,
"directlyConnected":true,
"interfaceIndex":1,
"interfaceName":"lo",
"active":true
}
]
}
],
"10.0.1.0\/24":[
{
"prefix":"10.0.1.0\/24",
"protocol":"isis",
"selected":true,
"distance":115,
"metric":10,
"nexthops":[
{
"fib":true,
"ip":"10.0.2.1",
"afi":"ipv4",
"interfaceIndex":3,
"interfaceName":"r3-eth1",
"active":true
},
{
"fib":true,
"ip":"10.0.3.2",
"afi":"ipv4",
"interfaceIndex":4,
"interfaceName":"r3-eth2",
"active":true
}
]
}
],
"10.0.2.0\/24":[
{
"prefix":"10.0.2.0\/24",
"protocol":"isis",
"distance":115,
"metric":10,
"nexthops":[
{
"ip":"10.0.2.1",
"afi":"ipv4",
"interfaceIndex":3,
"interfaceName":"r3-eth1"
}
]
},
{
"prefix":"10.0.2.0\/24",
"protocol":"connected",
"selected":true,
"nexthops":[
{
"fib":true,
"directlyConnected":true,
"interfaceIndex":3,
"interfaceName":"r3-eth1",
"active":true
}
]
}
],
"10.0.3.0\/24":[
{
"prefix":"10.0.3.0\/24",
"protocol":"isis",
"distance":115,
"metric":10,
"nexthops":[
{
"ip":"10.0.3.2",
"afi":"ipv4",
"interfaceIndex":4,
"interfaceName":"r3-eth2"
}
]
},
{
"prefix":"10.0.3.0\/24",
"protocol":"connected",
"selected":true,
"nexthops":[
{
"fib":true,
"directlyConnected":true,
"interfaceIndex":4,
"interfaceName":"r3-eth2",
"active":true
}
]
}
]
}

View File

@ -0,0 +1,16 @@
{
"1": {
"r3-eth1": [
{
"level": "Level-1",
"metric": "10"
}
],
"r3-eth2": [
{
"level": "Level-1",
"metric": "10"
}
]
}
}

View File

@ -0,0 +1,16 @@
{
"1": {
"r3-eth1": [
{
"level": "Level-1",
"metric": "10"
}
],
"r3-eth2": [
{
"level": "Level-1",
"metric": "10"
}
]
}
}

View File

@ -0,0 +1,16 @@
{
"1": {
"r3-eth1": [
{
"level": "Level-1",
"metric": "10"
}
],
"r3-eth2": [
{
"level": "Level-1",
"metric": "10"
}
]
}
}

View File

@ -0,0 +1,13 @@
{
"r3-eth1":{
"ldpIgpSyncEnabled":false,
"holdDownTimeInSec":50,
"ldpIgpSyncState":"Sync not required"
},
"r3-eth2":{
"ldpIgpSyncEnabled":true,
"holdDownTimeInSec":50,
"ldpIgpSyncState":"Sync achieved"
}
}

View File

@ -0,0 +1,13 @@
{
"r3-eth1":{
"ldpIgpSyncEnabled":false,
"holdDownTimeInSec":50,
"ldpIgpSyncState":"Sync not required"
},
"r3-eth2":{
"ldpIgpSyncEnabled":true,
"holdDownTimeInSec":50,
"ldpIgpSyncState":"Sync achieved"
}
}

View File

@ -0,0 +1,13 @@
{
"r3-eth1":{
"ldpIgpSyncEnabled":false,
"holdDownTimeInSec":50,
"ldpIgpSyncState":"Sync not required"
},
"r3-eth2":{
"ldpIgpSyncEnabled":true,
"holdDownTimeInSec":50,
"ldpIgpSyncState":"Sync achieved"
}
}

View File

@ -0,0 +1,2 @@
{
}

View File

@ -0,0 +1,2 @@
{
}

Some files were not shown because too many files have changed in this diff Show More