diff options
-rw-r--r-- | isisd/isis_bpf.c | 11 | ||||
-rw-r--r-- | isisd/isis_dlpi.c | 30 | ||||
-rw-r--r-- | isisd/isis_pdu.c | 92 | ||||
-rw-r--r-- | isisd/isis_pfpacket.c | 29 |
4 files changed, 114 insertions, 48 deletions
diff --git a/isisd/isis_bpf.c b/isisd/isis_bpf.c index 4d5b16513..1e70cc132 100644 --- a/isisd/isis_bpf.c +++ b/isisd/isis_bpf.c @@ -29,6 +29,7 @@ #include <net/bpf.h> #include "log.h" +#include "network.h" #include "stream.h" #include "if.h" @@ -338,8 +339,14 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level) /* now we can send this */ written = write (circuit->fd, sock_buff, buflen); - - return ISIS_OK; + if (written < 0) + { + zlog_warn("IS-IS bpf: could not transmit packet on %s: %s", + circuit->interface->name, safe_strerror(errno)); + if (ERRNO_IO_RETRY(errno)) + return ISIS_WARNING; + return ISIS_ERROR; + } } int diff --git a/isisd/isis_dlpi.c b/isisd/isis_dlpi.c index 0a82718d3..94ccdf5ab 100644 --- a/isisd/isis_dlpi.c +++ b/isisd/isis_dlpi.c @@ -33,6 +33,7 @@ #include <sys/pfmod.h> #include "log.h" +#include "network.h" #include "stream.h" #include "if.h" @@ -90,13 +91,14 @@ static u_short pf_filter[] = * interfaces plus the (optional; not needed) Solaris packet filter module. */ -static void +static int dlpisend (int fd, const void *cbuf, size_t cbuflen, const void *dbuf, size_t dbuflen, int flags) { const struct strbuf *ctlptr = NULL; const struct strbuf *dataptr = NULL; struct strbuf ctlbuf, databuf; + int rv; if (cbuf != NULL) { @@ -115,8 +117,16 @@ dlpisend (int fd, const void *cbuf, size_t cbuflen, } /* We assume this doesn't happen often and isn't operationally significant */ - if (putmsg (fd, ctlptr, dataptr, flags) == -1) - zlog_debug ("%s: putmsg: %s", __func__, safe_strerror (errno)); + rv = putmsg(fd, ctlptr, dataptr, flags); + if (rv == -1 && dbuf == NULL) + { + /* + * For actual PDU transmission - recognizable buf dbuf != NULL, + * the error is passed upwards and should not be printed here. + */ + zlog_debug ("%s: putmsg: %s", __func__, safe_strerror (errno)); + } + return rv; } static ssize_t @@ -586,6 +596,7 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level) char *dstaddr; u_short *dstsap; int buflen; + int rv; buflen = stream_get_endp (circuit->snd_stream) + LLC_LEN; if (buflen > sizeof (sock_buff)) @@ -625,8 +636,17 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level) sock_buff[2] = 0x03; memcpy (sock_buff + LLC_LEN, circuit->snd_stream->data, stream_get_endp (circuit->snd_stream)); - dlpisend (circuit->fd, dur, sizeof (*dur) + dur->dl_dest_addr_length, - sock_buff, buflen, 0); + rv = dlpisend(circuit->fd, dur, sizeof (*dur) + dur->dl_dest_addr_length, + sock_buff, buflen, 0); + if (rv < 0) + { + zlog_warn("IS-IS dlpi: could not transmit packet on %s: %s", + circuit->interface->name, safe_strerror(errno)); + if (ERRNO_IO_RETRY(errno)) + return ISIS_WARNING; + return ISIS_ERROR; + } + return ISIS_OK; } 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; } diff --git a/isisd/isis_pfpacket.c b/isisd/isis_pfpacket.c index 1bc5f763c..46c8edd68 100644 --- a/isisd/isis_pfpacket.c +++ b/isisd/isis_pfpacket.c @@ -26,6 +26,7 @@ #include <netpacket/packet.h> #include "log.h" +#include "network.h" #include "stream.h" #include "if.h" @@ -367,8 +368,14 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level) iov[1].iov_base = circuit->snd_stream->data; iov[1].iov_len = stream_get_endp (circuit->snd_stream); - sendmsg (circuit->fd, &msg, 0); - + if (sendmsg(circuit->fd, &msg, 0) < 0) + { + zlog_warn("IS-IS pfpacket: could not transmit packet on %s: %s", + circuit->interface->name, safe_strerror(errno)); + if (ERRNO_IO_RETRY(errno)) + return ISIS_WARNING; + return ISIS_ERROR; + } return ISIS_OK; } @@ -376,6 +383,7 @@ int isis_send_pdu_p2p (struct isis_circuit *circuit, int level) { struct sockaddr_ll sa; + ssize_t rv; stream_set_getp (circuit->snd_stream, 0); memset (&sa, 0, sizeof (struct sockaddr_ll)); @@ -391,11 +399,18 @@ isis_send_pdu_p2p (struct isis_circuit *circuit, int level) /* lets try correcting the protocol */ sa.sll_protocol = htons (0x00FE); - sendto (circuit->fd, circuit->snd_stream->data, - stream_get_endp (circuit->snd_stream), 0, - (struct sockaddr *) &sa, - sizeof (struct sockaddr_ll)); - + rv = sendto(circuit->fd, circuit->snd_stream->data, + stream_get_endp (circuit->snd_stream), 0, + (struct sockaddr *) &sa, + sizeof (struct sockaddr_ll)); + if (rv < 0) + { + zlog_warn("IS-IS pfpacket: could not transmit packet on %s: %s", + circuit->interface->name, safe_strerror(errno)); + if (ERRNO_IO_RETRY(errno)) + return ISIS_WARNING; + return ISIS_ERROR; + } return ISIS_OK; } |