summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaren Schoener <karen@voltanet.io>2020-07-22 18:10:59 +0200
committerlynne <lynne@voltanet.io>2020-09-09 16:45:41 +0200
commite1894ff70f77f39ae993f875a96d6cb1282ffd1a (patch)
tree2b626ddfa147660799e092679808e6e5fd6c055e
parentMerge pull request #5702 from vishaldhingra/bgp_nb (diff)
downloadfrr-e1894ff70f77f39ae993f875a96d6cb1282ffd1a.tar.xz
frr-e1894ff70f77f39ae993f875a96d6cb1282ffd1a.zip
ldpd: Adding support for LDP IGP Synchronization
Signed-off-by: Lynne Morrison <lynne@voltanet.io> Signed-off-by: Karen Schoener <karen@voltanet.io>
-rw-r--r--ldpd/adjacency.c3
-rw-r--r--ldpd/control.c3
-rw-r--r--ldpd/hello.c1
-rw-r--r--ldpd/interface.c417
-rw-r--r--ldpd/ldp.h2
-rw-r--r--ldpd/ldp_debug.c12
-rw-r--r--ldpd/ldp_debug.h10
-rw-r--r--ldpd/ldp_vty.h2
-rw-r--r--ldpd/ldp_vty_cmds.c28
-rw-r--r--ldpd/ldp_vty_conf.c24
-rw-r--r--ldpd/ldp_vty_exec.c121
-rw-r--r--ldpd/ldp_zebra.c110
-rw-r--r--ldpd/ldpd.c17
-rw-r--r--ldpd/ldpd.h52
-rw-r--r--ldpd/ldpe.c24
-rw-r--r--ldpd/ldpe.h11
-rw-r--r--ldpd/neighbor.c2
-rw-r--r--ldpd/packet.c2
-rw-r--r--lib/zclient.h8
19 files changed, 841 insertions, 8 deletions
diff --git a/ldpd/adjacency.c b/ldpd/adjacency.c
index 0bdd2423c..4e09a6c4c 100644
--- a/ldpd/adjacency.c
+++ b/ldpd/adjacency.c
@@ -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;
diff --git a/ldpd/control.c b/ldpd/control.c
index cde99dc8a..6554f0a6f 100644
--- a/ldpd/control.c
+++ b/ldpd/control.c
@@ -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;
diff --git a/ldpd/hello.c b/ldpd/hello.c
index ac24704bc..caf63c13d 100644
--- a/ldpd/hello.c
+++ b/ldpd/hello.c
@@ -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;
diff --git a/ldpd/interface.c b/ldpd/interface.c
index 371c7d0bb..bc8f26bc5 100644
--- a/ldpd/interface.c
+++ b/ldpd/interface.c
@@ -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);
+}
diff --git a/ldpd/ldp.h b/ldpd/ldp.h
index 5d1bf81ec..4bad3afc3 100644
--- a/ldpd/ldp.h
+++ b/ldpd/ldp.h
@@ -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
diff --git a/ldpd/ldp_debug.c b/ldpd/ldp_debug.c
index b9ef60ff9..a8d9833dd 100644
--- a/ldpd/ldp_debug.c
+++ b/ldpd/ldp_debug.c
@@ -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);
}
diff --git a/ldpd/ldp_debug.h b/ldpd/ldp_debug.h
index 8ae144d93..977734bdd 100644
--- a/ldpd/ldp_debug.h
+++ b/ldpd/ldp_debug.h
@@ -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_ */
diff --git a/ldpd/ldp_vty.h b/ldpd/ldp_vty.h
index f6ba8f8c9..882874f1b 100644
--- a/ldpd/ldp_vty.h
+++ b/ldpd/ldp_vty.h
@@ -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 *,
diff --git a/ldpd/ldp_vty_cmds.c b/ldpd/ldp_vty_cmds.c
index fc84c7f76..4e6257eaa 100644
--- a/ldpd/ldp_vty_cmds.c
+++ b/ldpd/ldp_vty_cmds.c
@@ -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));
@@ -693,6 +705,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\
@@ -817,6 +841,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);
@@ -886,4 +911,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);
}
diff --git a/ldpd/ldp_vty_conf.c b/ldpd/ldp_vty_conf.c
index 03dee23b4..c217cfc78 100644
--- a/ldpd/ldp_vty_conf.c
+++ b/ldpd/ldp_vty_conf.c
@@ -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)
{
diff --git a/ldpd/ldp_vty_exec.c b/ldpd/ldp_vty_exec.c
index d8ed5cccc..609598a76 100644
--- a/ldpd/ldp_vty_exec.c
+++ b/ldpd/ldp_vty_exec.c
@@ -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 *);
@@ -207,6 +211,87 @@ show_interface_msg_json(struct imsg *imsg, struct show_params *params,
}
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)
{
@@ -1437,6 +1522,20 @@ ldp_vty_dispatch_iface(struct vty *vty, struct imsg *imsg,
}
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);
}
@@ -1946,6 +2047,22 @@ ldp_vty_show_neighbor(struct vty *vty, const char *lsr_id, int capabilities,
}
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)
{
diff --git a/ldpd/ldp_zebra.c b/ldpd/ldp_zebra.c
index d828fbe97..16e9adc9d 100644
--- a/ldpd/ldp_zebra.c
+++ b/ldpd/ldp_zebra.c
@@ -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;
diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c
index 927c3a3c0..1c83ffb35 100644
--- a/ldpd/ldpd.c
+++ b/ldpd/ldpd.c
@@ -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)
diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h
index c1bcc56c4..f8a94b4e2 100644
--- a/ldpd/ldpd.h
+++ b/ldpd/ldpd.h
@@ -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__
diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c
index 655313bf1..29a37efb0 100644
--- a/ldpd/ldpe.c
+++ b/ldpd/ldpe.c
@@ -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);
@@ -979,6 +989,20 @@ ldpe_nbr_ctl(struct ctl_conn *c)
}
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)
{
struct mapping_entry *me;
diff --git a/ldpd/ldpe.h b/ldpd/ldpe.h
index 11650069b..ef4702341 100644
--- a/ldpd/ldpe.h
+++ b/ldpd/ldpe.h
@@ -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 *,
diff --git a/ldpd/neighbor.c b/ldpd/neighbor.c
index 6143beb6b..236d3eaa5 100644
--- a/ldpd/neighbor.c
+++ b/ldpd/neighbor.c
@@ -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;
diff --git a/ldpd/packet.c b/ldpd/packet.c
index c00008d12..3f73f8cd8 100644
--- a/ldpd/packet.c
+++ b/ldpd/packet.c
@@ -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);
diff --git a/lib/zclient.h b/lib/zclient.h
index dab384d5e..c49a850e3 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -950,6 +950,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.