ldpd: Adding support for LDP IGP Synchronization

Signed-off-by: Lynne Morrison <lynne@voltanet.io>
Signed-off-by: Karen Schoener <karen@voltanet.io>
This commit is contained in:
Karen Schoener 2020-07-22 12:10:59 -04:00 committed by lynne
parent f088c4e77d
commit e1894ff70f
19 changed files with 841 additions and 8 deletions

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));
@ -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);
}

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);
@ -978,6 +988,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

@ -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.