diff options
author | Christian Franke <chris@opensourcerouting.org> | 2015-11-12 14:24:28 +0100 |
---|---|---|
committer | Donald Sharp <sharpd@cumulusnetworks.com> | 2016-03-30 02:26:34 +0200 |
commit | cfd1f27b7103854a6c25fd0e05ee286ce01d62e9 (patch) | |
tree | d3ee1d766d74798da8cbd6eed582ca5a21607353 /isisd/isis_pdu.c | |
parent | isisd: fix misleading wording in log (diff) | |
download | frr-cfd1f27b7103854a6c25fd0e05ee286ce01d62e9.tar.xz frr-cfd1f27b7103854a6c25fd0e05ee286ce01d62e9.zip |
isisd: make send_lsp more robust
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
Tested-by: NetDEF CI System <cisystem@netdef.org>
Diffstat (limited to 'isisd/isis_pdu.c')
-rw-r--r-- | isisd/isis_pdu.c | 92 |
1 files changed, 58 insertions, 34 deletions
diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 984b949fb..d1caaa49a 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -3061,15 +3061,14 @@ send_lsp (struct thread *thread) struct isis_circuit *circuit; struct isis_lsp *lsp; struct listnode *node; + int clear_srm = 1; int retval = ISIS_OK; circuit = THREAD_ARG (thread); assert (circuit); - if (circuit->state != C_STATE_UP || circuit->is_passive == 1) - { - return retval; - } + if (!circuit->lsp_queue) + return ISIS_OK; node = listhead (circuit->lsp_queue); @@ -3079,28 +3078,56 @@ send_lsp (struct thread *thread) * thread gets a chance to run. */ if (!node) - { - return retval; - } + return ISIS_OK; + /* + * Delete LSP from lsp_queue. If it's still in queue, it is assumed + * as 'transmit pending', but send_lsp may never be called again. + * Retry will happen because SRM flag will not be cleared. + */ lsp = listgetdata(node); + list_delete_node (circuit->lsp_queue, node); + + /* Set the last-cleared time if the queue is empty. */ + /* TODO: Is is possible that new lsps keep being added to the queue + * that the queue is never empty? */ + if (list_isempty (circuit->lsp_queue)) + circuit->lsp_queue_last_cleared = time (NULL); + + if (circuit->state != C_STATE_UP || circuit->is_passive == 1) + goto out; /* * Do not send if levels do not match */ if (!(lsp->level & circuit->is_type)) - { - list_delete_node (circuit->lsp_queue, node); - return retval; - } + goto out; /* * Do not send if we do not have adjacencies in state up on the circuit */ if (circuit->upadjcount[lsp->level - 1] == 0) - { - list_delete_node (circuit->lsp_queue, node); - return retval; + goto out; + + /* stream_copy will assert and stop program execution if LSP is larger than + * the circuit's MTU. So handle and log this case here. */ + if (stream_get_endp(lsp->pdu) > stream_get_size(circuit->snd_stream)) + { + zlog_err("ISIS-Upd (%s): Can't send L%d LSP %s, seq 0x%08x," + " cksum 0x%04x, lifetime %us on %s. LSP Size is %zu" + " while interface stream size is %zu.", + circuit->area->area_tag, lsp->level, + rawlspid_print(lsp->lsp_header->lsp_id), + ntohl(lsp->lsp_header->seq_num), + ntohs(lsp->lsp_header->checksum), + ntohs(lsp->lsp_header->rem_lifetime), + circuit->interface->name, + stream_get_endp(lsp->pdu), + stream_get_size(circuit->snd_stream)); + if (isis->debugs & DEBUG_PACKET_DUMP) + zlog_dump_data(STREAM_DATA(lsp->pdu), stream_get_endp(lsp->pdu)); + retval = ISIS_ERROR; + goto out; } /* copy our lsp to the send buffer */ @@ -3121,32 +3148,29 @@ send_lsp (struct thread *thread) stream_get_endp (circuit->snd_stream)); } + clear_srm = 0; retval = circuit->tx (circuit, lsp->level); if (retval != ISIS_OK) { - zlog_err ("ISIS-Upd (%s): Send L%d LSP on %s failed", + zlog_err ("ISIS-Upd (%s): Send L%d LSP on %s failed %s", circuit->area->area_tag, lsp->level, - circuit->interface->name); - return retval; + circuit->interface->name, + (retval == ISIS_WARNING) ? "temporarily" : "permanently"); } - /* - * If the sending succeeded, we can del the lsp from circuits - * lsp_queue - */ - list_delete_node (circuit->lsp_queue, node); - - /* Set the last-cleared time if the queue is empty. */ - /* TODO: Is is possible that new lsps keep being added to the queue - * that the queue is never empty? */ - if (list_isempty (circuit->lsp_queue)) - circuit->lsp_queue_last_cleared = time (NULL); - - /* - * On broadcast circuits also the SRMflag can be cleared - */ - if (circuit->circ_type == CIRCUIT_T_BROADCAST) - ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); +out: + if (clear_srm + || (retval == ISIS_OK && circuit->circ_type == CIRCUIT_T_BROADCAST) + || (retval != ISIS_OK && retval != ISIS_WARNING)) + { + /* SRM flag will trigger retransmission. We will not retransmit if we + * encountered a fatal error. + * On success, they should only be cleared if it's a broadcast circuit. + * On a P2P circuit, we will wait for the ack from the neighbor to clear + * the fag. + */ + ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); + } return retval; } |