summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRenato Westphal <renato@opensourcerouting.org>2017-06-13 15:32:24 +0200
committerRenato Westphal <renato@opensourcerouting.org>2017-06-13 18:21:16 +0200
commit0e3451e5cf761d877f5b99f8ac8acad0236dd4ab (patch)
tree2893106ff1b503e5a263ea3f0f11519c6a3e4b24
parentMerge pull request #681 (ASAN warnings) (diff)
downloadfrr-0e3451e5cf761d877f5b99f8ac8acad0236dd4ab.tar.xz
frr-0e3451e5cf761d877f5b99f8ac8acad0236dd4ab.zip
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 <renato@opensourcerouting.org>
-rw-r--r--ldpd/adjacency.c22
-rw-r--r--ldpd/hello.c17
2 files changed, 18 insertions, 21 deletions
diff --git a/ldpd/adjacency.c b/ldpd/adjacency.c
index 3ec57f158..89314aa2c 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 dd67f68f7..d17e80008 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);