isisd: fix crash on "no router isis" (BZ#536)
The crash is due to threads accessing data that gets destroyed
during the removal of the configuration.
* isis_circuit.c: Destroy adjacencies to stop adjacency expiry thread.
Stop PSNP threads.
* isisd.c: Change state of circuit back to INIT and reassign the
circuit structure to isis->init_circ_list rather than destroying
the circuit data structure. Stop SPF threads. Stop LSP generation
threads.
* isisd.h: Add pointers to LSP threads into area structure in order to
stop them in isisd.c
* isis_lsp.c: Store pointer to LSP thread in area structure.
* isis_pdu.c: Stop PDU generation for a circuit with a removed area.
* isis_pfpacket.c: Stop processing received PDUs for a circuit with a
removed area.
diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c
index d2923b5..e34d491 100644
--- a/isisd/isis_circuit.c
+++ b/isisd/isis_circuit.c
@@ -142,6 +142,11 @@
struct isis_area *area)
{
+ /* destroy adjacencies */
+ if (circuit->u.bc.adjdb[0])
+ isis_adjdb_iterate (circuit->u.bc.adjdb[0], (void(*) (struct isis_adjacency *, void *)) isis_delete_adj, circuit->u.bc.adjdb[0]);
+ if (circuit->u.bc.adjdb[1])
+ isis_adjdb_iterate (circuit->u.bc.adjdb[1], (void(*) (struct isis_adjacency *, void *)) isis_delete_adj, circuit->u.bc.adjdb[1]);
/* Remove circuit from area */
listnode_delete (area->circuit_list, circuit);
/* Free the index of SRM and SSN flags */
@@ -602,6 +607,13 @@
{
THREAD_TIMER_OFF (circuit->u.p2p.t_send_p2p_hello);
}
+
+ if (circuit->t_send_psnp[0]) {
+ THREAD_TIMER_OFF (circuit->t_send_psnp[0]);
+ }
+ if (circuit->t_send_psnp[1]) {
+ THREAD_TIMER_OFF (circuit->t_send_psnp[1]);
+ }
/* close the socket */
close (circuit->fd);
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
index 50289db..e12e4ca 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -1640,7 +1640,7 @@
if (diff < MIN_LSP_GEN_INTERVAL)
{
area->lsp_regenerate_pending[0] = 1;
- thread_add_timer (master, lsp_l1_regenerate, area,
+ area->t_lsp_l1_regenerate=thread_add_timer (master, lsp_l1_regenerate, area,
MIN_LSP_GEN_INTERVAL - diff);
goto L2;
}
@@ -1663,7 +1663,7 @@
if (diff < MIN_LSP_GEN_INTERVAL)
{
area->lsp_regenerate_pending[1] = 1;
- thread_add_timer (master, lsp_l2_regenerate, area,
+ area->t_lsp_l2_regenerate=thread_add_timer (master, lsp_l2_regenerate, area,
MIN_LSP_GEN_INTERVAL - diff);
return ISIS_OK;
}
diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c
index 8219e83..34e4b03 100644
--- a/isisd/isis_pdu.c
+++ b/isisd/isis_pdu.c
@@ -1781,6 +1781,9 @@
circuit = THREAD_ARG (thread);
assert (circuit);
+ if (!circuit->area)
+ return ISIS_OK;
+
if (circuit->rcv_stream == NULL)
circuit->rcv_stream = stream_new (ISO_MTU (circuit));
else
@@ -2088,6 +2091,11 @@
circuit = THREAD_ARG (thread);
assert (circuit);
+
+ if (!circuit->area) {
+ return ISIS_OK;
+ }
+
circuit->u.bc.t_send_lan_hello[1] = NULL;
if (circuit->u.bc.run_dr_elect[1])
diff --git a/isisd/isis_pfpacket.c b/isisd/isis_pfpacket.c
index 9e4165e..8a5c3ed 100644
--- a/isisd/isis_pfpacket.c
+++ b/isisd/isis_pfpacket.c
@@ -232,6 +232,10 @@
LLC_LEN, MSG_PEEK,
(struct sockaddr *) &s_addr, (socklen_t *) &addr_len);
+ if (!circuit->area) {
+ return ISIS_OK;
+ }
+
if (bytesread < 0)
{
zlog_warn ("isis_recv_packet_bcast(): fd %d, recvfrom (): %s",
diff --git a/isisd/isisd.c b/isisd/isisd.c
index 1e84a1c..20a3280 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -52,6 +52,7 @@
#include "isisd/isis_route.h"
#include "isisd/isis_zebra.h"
#include "isisd/isis_events.h"
+#include "isisd/isis_csm.h"
#ifdef TOPOLOGY_GENERATE
#include "spgrid.h"
@@ -217,21 +218,31 @@
for (ALL_LIST_ELEMENTS (area->circuit_list, node, nnode, circuit))
{
/* The fact that it's in circuit_list means that it was configured */
+ isis_csm_state_change (ISIS_DISABLE, circuit, area);
+ isis_circuit_down (circuit);
isis_circuit_deconfigure (circuit, area);
- isis_circuit_del (circuit);
}
list_delete (area->circuit_list);
}
listnode_delete (isis->area_list, area);
+
THREAD_TIMER_OFF (area->t_tick);
if (area->t_remove_aged)
thread_cancel (area->t_remove_aged);
THREAD_TIMER_OFF (area->t_lsp_refresh[0]);
THREAD_TIMER_OFF (area->t_lsp_refresh[1]);
+ THREAD_TIMER_OFF (area->spftree[0]->t_spf);
+ THREAD_TIMER_OFF (area->spftree[1]->t_spf);
+
+ THREAD_TIMER_OFF (area->t_lsp_l1_regenerate);
+ THREAD_TIMER_OFF (area->t_lsp_l2_regenerate);
+
XFREE (MTYPE_ISIS_AREA, area);
+ isis->sysid_set=0;
+
return CMD_SUCCESS;
}
diff --git a/isisd/isisd.h b/isisd/isisd.h
index 2277f27..b17982e 100644
--- a/isisd/isisd.h
+++ b/isisd/isisd.h
@@ -93,6 +93,8 @@
struct flags flags;
struct thread *t_tick; /* LSP walker */
struct thread *t_remove_aged;
+ struct thread *t_lsp_l1_regenerate;
+ struct thread *t_lsp_l2_regenerate;
int lsp_regenerate_pending[ISIS_LEVELS];
struct thread *t_lsp_refresh[ISIS_LEVELS];