From 0e3451e5cf761d877f5b99f8ac8acad0236dd4ab Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Tue, 13 Jun 2017 10:32:24 -0300 Subject: [PATCH] ldpd: fix issues with dual-stack adjacencies Handling configuration changes from single-stack mode to dual-stack mode (and vice-versa) is tricky. This patch attempts to solve all issues that might happen on such circumstances. Signed-off-by: Renato Westphal --- ldpd/adjacency.c | 22 ++++++---------------- ldpd/hello.c | 17 ++++++++++++----- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/ldpd/adjacency.c b/ldpd/adjacency.c index 3ec57f1589..89314aa2c3 100644 --- a/ldpd/adjacency.c +++ b/ldpd/adjacency.c @@ -109,17 +109,19 @@ adj_new(struct in_addr lsr_id, struct hello_source *source, return (adj); } -static void -adj_del_single(struct adj *adj) +void +adj_del(struct adj *adj, uint32_t notif_status) { + struct nbr *nbr = adj->nbr; + log_debug("%s: lsr-id %s, %s (%s)", __func__, inet_ntoa(adj->lsr_id), log_hello_src(&adj->source), af_name(adj_get_af(adj))); adj_stop_itimer(adj); RB_REMOVE(global_adj_head, &global.adj_tree, adj); - if (adj->nbr) - RB_REMOVE(nbr_adj_head, &adj->nbr->adj_tree, adj); + if (nbr) + RB_REMOVE(nbr_adj_head, &nbr->adj_tree, adj); switch (adj->source.type) { case HELLO_LINK: RB_REMOVE(ia_adj_head, &adj->source.link.ia->adj_tree, adj); @@ -130,15 +132,6 @@ adj_del_single(struct adj *adj) } free(adj); -} - -void -adj_del(struct adj *adj, uint32_t notif_status) -{ - struct nbr *nbr = adj->nbr; - struct adj *atmp; - - adj_del_single(adj); /* * If the neighbor still exists but none of its remaining @@ -146,8 +139,6 @@ adj_del(struct adj *adj, uint32_t notif_status) * then delete it. */ if (nbr && nbr_adj_count(nbr, nbr->af) == 0) { - RB_FOREACH_SAFE(adj, nbr_adj_head, &nbr->adj_tree, atmp) - adj_del_single(adj); session_shutdown(nbr, notif_status, 0, 0); nbr_del(nbr); } @@ -194,7 +185,6 @@ adj_itimer(struct thread *thread) tnbr_del(leconf, adj->source.target); return (0); } - adj->source.target->adj = NULL; } adj_del(adj, S_HOLDTIME_EXP); diff --git a/ldpd/hello.c b/ldpd/hello.c index dd67f68f70..d17e80008e 100644 --- a/ldpd/hello.c +++ b/ldpd/hello.c @@ -214,6 +214,7 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *msg, int af, __func__, inet_ntoa(lsr_id)); return; } + ds_tlv = (tlvs_rcvd & F_HELLO_TLV_RCVD_DS) ? 1 : 0; /* implicit transport address */ if (!(tlvs_rcvd & F_HELLO_TLV_RCVD_ADDR)) @@ -291,11 +292,21 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *msg, int af, source.link.src_addr = *src; } + debug_hello_recv("%s lsr-id %s transport-address %s holdtime %u%s", + log_hello_src(&source), inet_ntoa(lsr_id), log_addr(af, &trans_addr), + holdtime, (ds_tlv) ? " (dual stack TLV present)" : ""); + adj = adj_find(lsr_id, &source); + if (adj && adj->ds_tlv != ds_tlv) { + /* + * Transient condition, ignore packet and wait until adjacency + * times out. + */ + return; + } nbr = nbr_find_ldpid(lsr_id.s_addr); /* check dual-stack tlv */ - ds_tlv = (tlvs_rcvd & F_HELLO_TLV_RCVD_DS) ? 1 : 0; if (ds_tlv && trans_pref != leconf->trans_pref) { /* * RFC 7552 - Section 6.1.1: @@ -420,10 +431,6 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *msg, int af, else adj_stop_itimer(adj); - debug_hello_recv("%s lsr-id %s transport-address %s holdtime %u%s", - log_hello_src(&source), inet_ntoa(lsr_id), log_addr(af, &trans_addr), - holdtime, (ds_tlv) ? " (dual stack TLV present)" : ""); - if (nbr && nbr->state == NBR_STA_PRESENT && !nbr_pending_idtimer(nbr) && nbr_session_active_role(nbr) && !nbr_pending_connect(nbr)) nbr_establish_connection(nbr);