summaryrefslogtreecommitdiff
path: root/bgpd/bgp_packet.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_packet.c')
-rw-r--r--bgpd/bgp_packet.c140
1 files changed, 81 insertions, 59 deletions
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index b29bc1f0..ed2cb73e 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -177,10 +177,11 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi)
if (rn->prn)
prd = (struct prefix_rd *) &rn->prn->p;
- if (binfo && binfo->extra)
+ if (binfo)
{
- tag = binfo->extra->tag;
from = binfo->peer;
+ if (binfo->extra)
+ tag = binfo->extra->tag;
}
bgp_packet_set_marker (s, BGP_MSG_UPDATE);
@@ -597,7 +598,6 @@ bgp_write (struct thread *thread)
struct stream *s;
int num;
unsigned int count = 0;
- int write_errno;
/* Yes first of all get peer pointer. */
peer = THREAD_ARG (thread);
@@ -610,46 +610,37 @@ bgp_write (struct thread *thread)
return 0;
}
- /* Nonblocking write until TCP output buffer is full. */
- while (1)
+ s = bgp_write_packet (peer);
+ if (!s)
+ return 0; /* nothing to send */
+
+ sockopt_cork (peer->fd, 1);
+
+ /* Nonblocking write until TCP output buffer is full. */
+ do
{
int writenum;
- int val;
-
- s = bgp_write_packet (peer);
- if (! s)
- return 0;
-
- /* XXX: FIXME, the socket should be NONBLOCK from the start
- * status shouldnt need to be toggled on each write
- */
- val = fcntl (peer->fd, F_GETFL, 0);
- fcntl (peer->fd, F_SETFL, val|O_NONBLOCK);
/* Number of bytes to be sent. */
writenum = stream_get_endp (s) - stream_get_getp (s);
/* Call write() system call. */
num = write (peer->fd, STREAM_PNT (s), writenum);
- write_errno = errno;
- fcntl (peer->fd, F_SETFL, val);
- if (num <= 0)
+ if (num < 0)
{
- /* Partial write. */
- if (write_errno == EWOULDBLOCK || write_errno == EAGAIN)
- break;
+ /* write failed either retry needed or error */
+ if (ERRNO_IO_RETRY(errno))
+ break;
- BGP_EVENT_ADD (peer, TCP_fatal_error);
+ BGP_EVENT_ADD (peer, TCP_fatal_error);
return 0;
}
+
if (num != writenum)
{
+ /* Partial write */
stream_forward_getp (s, num);
-
- if (write_errno == EAGAIN)
- break;
-
- continue;
+ break;
}
/* Retrieve BGP packet type. */
@@ -690,13 +681,14 @@ bgp_write (struct thread *thread)
/* OK we send packet so delete it. */
bgp_packet_delete (peer);
-
- if (++count >= BGP_WRITE_PACKET_MAX)
- break;
}
+ while (++count < BGP_WRITE_PACKET_MAX &&
+ (s = bgp_write_packet (peer)) != NULL);
if (bgp_write_proceed (peer))
BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
+ else
+ sockopt_cork (peer->fd, 0);
return 0;
}
@@ -705,7 +697,7 @@ bgp_write (struct thread *thread)
static int
bgp_write_notify (struct peer *peer)
{
- int ret;
+ int ret, val;
u_char type;
struct stream *s;
@@ -715,7 +707,10 @@ bgp_write_notify (struct peer *peer)
return 0;
assert (stream_get_endp (s) >= BGP_HEADER_SIZE);
- /* I'm not sure fd is writable. */
+ /* Put socket in blocking mode. */
+ val = fcntl (peer->fd, F_GETFL, 0);
+ fcntl (peer->fd, F_SETFL, val & ~O_NONBLOCK);
+
ret = writen (peer->fd, STREAM_DATA (s), stream_get_endp (s));
if (ret <= 0)
{
@@ -1884,12 +1879,6 @@ bgp_notify_receive (struct peer *peer, bgp_size_t size)
bgp_notify.subcode == BGP_NOTIFY_OPEN_UNSUP_PARAM )
UNSET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN);
- /* Also apply to Unsupported Capability until remote router support
- capability. */
- if (bgp_notify.code == BGP_NOTIFY_OPEN_ERR &&
- bgp_notify.subcode == BGP_NOTIFY_OPEN_UNSUP_CAPBL)
- UNSET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN);
-
BGP_EVENT_ADD (peer, Receive_NOTIFICATION_message);
}
@@ -2016,8 +2005,14 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
while (p_pnt < p_end)
{
+ /* If the ORF entry is malformed, want to read as much of it
+ * as possible without going beyond the bounds of the entry,
+ * to maximise debug information.
+ */
+ int ok;
memset (&orfp, 0, sizeof (struct orf_prefix));
common = *p_pnt++;
+ /* after ++: p_pnt <= p_end */
if (common & ORF_COMMON_PART_REMOVE_ALL)
{
if (BGP_DEBUG (normal, NORMAL))
@@ -2025,34 +2020,60 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
prefix_bgp_orf_remove_all (name);
break;
}
- memcpy (&seq, p_pnt, sizeof (u_int32_t));
- p_pnt += sizeof (u_int32_t);
- orfp.seq = ntohl (seq);
- orfp.ge = *p_pnt++;
- orfp.le = *p_pnt++;
- orfp.p.prefixlen = *p_pnt++;
- orfp.p.family = afi2family (afi);
- psize = PSIZE (orfp.p.prefixlen);
- memcpy (&orfp.p.u.prefix, p_pnt, psize);
+ ok = ((p_end - p_pnt) >= sizeof(u_int32_t)) ;
+ if (!ok)
+ {
+ memcpy (&seq, p_pnt, sizeof (u_int32_t));
+ p_pnt += sizeof (u_int32_t);
+ orfp.seq = ntohl (seq);
+ }
+ else
+ p_pnt = p_end ;
+
+ if ((ok = (p_pnt < p_end)))
+ orfp.ge = *p_pnt++ ; /* value checked in prefix_bgp_orf_set() */
+ if ((ok = (p_pnt < p_end)))
+ orfp.le = *p_pnt++ ; /* value checked in prefix_bgp_orf_set() */
+ if ((ok = (p_pnt < p_end)))
+ orfp.p.prefixlen = *p_pnt++ ;
+ orfp.p.family = afi2family (afi); /* afi checked already */
+
+ psize = PSIZE (orfp.p.prefixlen); /* 0 if not ok */
+ if (psize > prefix_blen(&orfp.p)) /* valid for family ? */
+ {
+ ok = 0 ;
+ psize = prefix_blen(&orfp.p) ;
+ }
+ if (psize > (p_end - p_pnt)) /* valid for packet ? */
+ {
+ ok = 0 ;
+ psize = p_end - p_pnt ;
+ }
+
+ if (psize > 0)
+ memcpy (&orfp.p.u.prefix, p_pnt, psize);
p_pnt += psize;
if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s rcvd %s %s seq %u %s/%d ge %d le %d",
+ zlog_debug ("%s rcvd %s %s seq %u %s/%d ge %d le %d%s",
peer->host,
(common & ORF_COMMON_PART_REMOVE ? "Remove" : "Add"),
(common & ORF_COMMON_PART_DENY ? "deny" : "permit"),
orfp.seq,
inet_ntop (orfp.p.family, &orfp.p.u.prefix, buf, BUFSIZ),
- orfp.p.prefixlen, orfp.ge, orfp.le);
-
- ret = prefix_bgp_orf_set (name, afi, &orfp,
- (common & ORF_COMMON_PART_DENY ? 0 : 1 ),
- (common & ORF_COMMON_PART_REMOVE ? 0 : 1));
-
- if (ret != CMD_SUCCESS)
+ orfp.p.prefixlen, orfp.ge, orfp.le,
+ ok ? "" : " MALFORMED");
+
+ if (ok)
+ ret = prefix_bgp_orf_set (name, afi, &orfp,
+ (common & ORF_COMMON_PART_DENY ? 0 : 1 ),
+ (common & ORF_COMMON_PART_REMOVE ? 0 : 1));
+
+ if (!ok || (ret != CMD_SUCCESS))
{
if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s Received misformatted prefixlist ORF. Remove All pfxlist", peer->host);
+ zlog_debug ("%s Received misformatted prefixlist ORF."
+ " Remove All pfxlist", peer->host);
prefix_bgp_orf_remove_all (name);
break;
}
@@ -2237,12 +2258,13 @@ bgp_read_packet (struct peer *peer)
return 0;
/* Read packet from fd. */
- nbytes = stream_read_unblock (peer->ibuf, peer->fd, readsize);
+ nbytes = stream_read_try (peer->ibuf, peer->fd, readsize);
/* If read byte is smaller than zero then error occured. */
if (nbytes < 0)
{
- if (errno == EAGAIN)
+ /* Transient error should retry */
+ if (nbytes == -2)
return -1;
plog_err (peer->log, "%s [Error] bgp_read_packet error: %s",