forked from Mirror/frr
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:
parent
f088c4e77d
commit
e1894ff70f
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
417
ldpd/interface.c
417
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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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 *,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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, ¶ms));
|
||||
}
|
||||
|
||||
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(¶ms, 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, ¶ms));
|
||||
}
|
||||
|
||||
int
|
||||
ldp_vty_show_atom_binding(struct vty *vty, const char *peer,
|
||||
unsigned long local_label, unsigned long remote_label, const char *json)
|
||||
|
|
110
ldpd/ldp_zebra.c
110
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;
|
||||
|
|
17
ldpd/ldpd.c
17
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)
|
||||
|
|
52
ldpd/ldpd.h
52
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__
|
||||
|
|
24
ldpd/ldpe.c
24
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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
|
11
ldpd/ldpe.h
11
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 *,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue