diff options
author | Karen Schoener <karen@voltanet.io> | 2020-07-22 18:10:59 +0200 |
---|---|---|
committer | lynne <lynne@voltanet.io> | 2020-09-09 16:45:41 +0200 |
commit | e1894ff70f77f39ae993f875a96d6cb1282ffd1a (patch) | |
tree | 2b626ddfa147660799e092679808e6e5fd6c055e | |
parent | Merge pull request #5702 from vishaldhingra/bgp_nb (diff) | |
download | frr-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.c | 3 | ||||
-rw-r--r-- | ldpd/control.c | 3 | ||||
-rw-r--r-- | ldpd/hello.c | 1 | ||||
-rw-r--r-- | ldpd/interface.c | 417 | ||||
-rw-r--r-- | ldpd/ldp.h | 2 | ||||
-rw-r--r-- | ldpd/ldp_debug.c | 12 | ||||
-rw-r--r-- | ldpd/ldp_debug.h | 10 | ||||
-rw-r--r-- | ldpd/ldp_vty.h | 2 | ||||
-rw-r--r-- | ldpd/ldp_vty_cmds.c | 28 | ||||
-rw-r--r-- | ldpd/ldp_vty_conf.c | 24 | ||||
-rw-r--r-- | ldpd/ldp_vty_exec.c | 121 | ||||
-rw-r--r-- | ldpd/ldp_zebra.c | 110 | ||||
-rw-r--r-- | ldpd/ldpd.c | 17 | ||||
-rw-r--r-- | ldpd/ldpd.h | 52 | ||||
-rw-r--r-- | ldpd/ldpe.c | 24 | ||||
-rw-r--r-- | ldpd/ldpe.h | 11 | ||||
-rw-r--r-- | ldpd/neighbor.c | 2 | ||||
-rw-r--r-- | ldpd/packet.c | 2 | ||||
-rw-r--r-- | lib/zclient.h | 8 |
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(¶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) { 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. |