summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--bgpd/Makefile.am7
-rw-r--r--bgpd/bgp.h62
-rw-r--r--bgpd/bgp_common.h18
-rw-r--r--bgpd/bgp_connection.c101
-rw-r--r--bgpd/bgp_connection.h56
-rw-r--r--bgpd/bgp_fsm.c79
-rw-r--r--bgpd/bgp_msg_write.c2902
-rw-r--r--bgpd/bgp_msg_write.h112
-rw-r--r--bgpd/bgp_notification.c20
-rw-r--r--bgpd/bgp_notification.h109
-rw-r--r--bgpd/bgp_open_state.c72
-rw-r--r--bgpd/bgp_open_state.h37
-rw-r--r--bgpd/bgp_packet.h16
-rw-r--r--bgpd/bgp_route_refresh.c186
-rw-r--r--bgpd/bgp_route_refresh.h135
-rw-r--r--bgpd/bgp_session.c4
-rw-r--r--bgpd/bgp_session.h14
-rw-r--r--lib/Makefile.am2
-rw-r--r--lib/confirm.h28
-rw-r--r--lib/memtypes.c2
-rw-r--r--lib/stream.c14
-rw-r--r--lib/stream.h1
-rw-r--r--lib/zassert.h15
24 files changed, 1422 insertions, 2572 deletions
diff --git a/.gitignore b/.gitignore
index 79aebd73..19167ce9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -39,3 +39,5 @@ build
.project
.settings/
m4/*.m4
+commit.log
+
diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am
index 3788e0f3..69f42c9a 100644
--- a/bgpd/Makefile.am
+++ b/bgpd/Makefile.am
@@ -17,7 +17,8 @@ libbgp_a_SOURCES = \
bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_mplsvpn.c bgp_nexthop.c \
bgp_peer.c bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c \
bgp_engine.c bgp_session.c bgp_connection.c \
- bgp_common.c bgp_notification.c bgp_peer_index.c bgp_msg_write.c
+ bgp_common.c bgp_notification.c bgp_peer_index.c bgp_msg_write.c \
+ bgp_route_refresh.c
noinst_HEADERS = \
bgp_aspath.h bgp_attr.h bgp_community.h bgp_debug.h bgp_fsm.h \
@@ -26,8 +27,8 @@ noinst_HEADERS = \
bgp_ecommunity.h bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \
bgp_peer.h bgp_advertise.h bgp_snmp.h bgp_vty.h \
bgp_engine.h bgp_session.h bgp_connection.h \
- bgp_common.h bgp_notification.h bgp_peer_index.h bgp_msg_write.h
- bgp.h
+ bgp_common.h bgp_notification.h bgp_peer_index.h bgp_msg_write.h \
+ bgp_route_refresh.h bgp.h
bgpd_SOURCES = bgp_main.c
bgpd_LDADD = libbgp.a ../lib/libzebra.la @LIBCAP@ @LIBM@
diff --git a/bgpd/bgp.h b/bgpd/bgp.h
index 79415cd4..3b4f603c 100644
--- a/bgpd/bgp.h
+++ b/bgpd/bgp.h
@@ -28,19 +28,10 @@
* These are independent of Quagga.
*/
-/*==============================================================================
- * BGP Finite State Machine (FSM)
- */
-
-
-#endif /* _QUAGGA_BGP_H */
-
#define _GMCH_BGP_H "19-Dec-2009"
-#ifdef _GMCH_BGP_H
-
-#include "zassert.h"
#include <stdint.h>
+#include "confirm.h"
/*##############################################################################
* BGP RFC's we know about -- as of 16-Oct-2009
@@ -141,25 +132,30 @@ typedef uint32_t asn_t ; /* general ASN */
typedef uint16_t as2_t ; /* specifically 2 Octet ASN */
typedef uint32_t as4_t ; /* specifically 4 Octet ASN -- RFC4893 */
+typedef enum asn_type asn_type_t ;
enum asn_type
{
AS2 = 2,
AS4 = 4
} ;
-typedef enum asn_type asn_type_t ;
-
/* Other stuff.... */
-typedef uint32_t bgp_id_t ; /* actually an IPv4 IP Address */
+typedef uint32_t bgp_id_t ; /* actually an IPv4 IP Address */
+
+typedef bgp_id_t bgp_id_ht ; /* in host order */
+typedef bgp_id_t bgp_id_nt ; /* in network order */
-VALUE(BGP_MAX_NEXT_HOP_L = 32) ; /* maximum expected Next Hop address length */
+/* Size of BGP packets or thing in such */
+typedef uint16_t bgp_size_t;
+
+VALUE(BGP_NEXT_HOP_MAX_L = 32) ; /* maximum expected Next Hop address length */
/*==============================================================================
* BGP Message Structure
*/
-VALUE(BGP_MAX_MSG_L = 4096) ; /* RFC4271 hard limit on message length */
+VALUE(BGP_MSG_MAX_L = 4096) ; /* RFC4271 hard limit on message length */
/* Message Header Format ----------------------------------------------------*/
@@ -174,7 +170,7 @@ VALUE(BGP_MH_HEAD_L = /* message header length */
+ sizeof(BGP_MH_TYPE_T) ) ;
CONFIRM(BGP_MH_HEAD_L == 19) ; /* well known value ! */
-#define BGP_MAX_BODY_L (BGP_MAX_MSG_L - BGP_MH_HEAD_L)
+VALUE(BGP_MSG_BODY_MAX_L = BGP_MSG_MAX_L - BGP_MH_HEAD_L) ;
enum /* order of entries in Message Header */
{
@@ -197,6 +193,8 @@ enum BGP_MT
BGP_MT_ROUTE_REFRESH = 5, /* RFC2918 */
BGP_MT_MAX = 5, /* max known message type */
+
+ BGP_MT_ROUTE_REFRESH_pre = 128 /* pre RFC2918 (Sep-2000) */
} ;
/* Open Message (type = BGP_MT_OPEN) -------------------------------------------
@@ -292,6 +290,9 @@ enum BGP_CAN {
BGP_CAN_ADD_PATH = 69, /* ADD-PATH [draft-idr] */
BGP_CAN_MAX = 69, /* but mind the gap(s) ! */
+
+ BGP_CAN_R_REFRESH_pre = 128, /* pre-RFC value */
+ BGP_CAN_ORF_pre = 130, /* pre-RFC value */
} ;
/* Update Message (type = BGP_MT_UPDATE) ---------------------------------------
@@ -556,6 +557,12 @@ enum /* order */
BGP_RRM_ORFS, /* start of ORF collections */
} ;
+enum /* values for the BGP_RRM_ORF_WHEN byte */
+{
+ BGP_ORF_WTR_IMMEDIATE = 1, /* when-to-refresh == immediately */
+ BGP_ORF_WTR_DEFER = 2 /* when-to-refresh == defer */
+} ;
+
/* ORFS come in collections...................................................*/
typedef U8 BGP_ORF_TYPE_T ; /* ORF Type */
@@ -577,6 +584,8 @@ enum /* order */
typedef U8 BGP_ORF_E_ACTION_T ; /* see below for action/match bits */
typedef UBX BGP_ORF_E_REST_T ; /* rest depends on ORF Type */
+VALUE(BGP_ORF_E_COM_L = sizeof(BGP_ORF_E_ACTION_T)) ;
+
/* Known BGP_ORF_TYPE values..................................................*/
enum BGP_ORF {
@@ -584,19 +593,22 @@ enum BGP_ORF {
BGP_ORF_T_PREFIX = 64, /* Address Prefix ORF RFC5292 */
- BGP_ORF_T_MAX = 64
+ BGP_ORF_T_MAX = 64,
+
+ BGP_ORF_T_PREFIX_pre = 128 /* pre RFC value */
} ;
/* Known BGP_ORF_E_ACTION bits................................................*/
enum {
- BGP_ORF_EA_MASK = 0xC0, /* mask to extract Action */
+ BGP_ORF_EA_MASK = 0x3 << 6, /* mask to extract Action */
- BGP_ORF_EA_ADD = 0x00, /* Action: add ORF */
- BGP_ORF_EA_REMOVE = 0x40, /* Action: remove ORF */
- BGP_ORF_EA_REM_ALL = 0x80, /* Action: remove all ORF */
+ BGP_ORF_EA_ADD = 0 << 6, /* Action: ADD */
+ BGP_ORF_EA_REMOVE = 1 << 6, /* Action: REMOVE */
+ BGP_ORF_EA_RM_ALL = 2 << 6, /* Action: REMOVE-ALL */
- BGP_ORF_EA_DENY = 0x20, /* deny -- otherwise permit */
+ BGP_ORF_EA_PERMIT = 0 << 5, /* Match: PERMIT */
+ BGP_ORF_EA_DENY = 1 << 5, /* Match: DENY */
} ;
/* Address Prefix ORF (BGP_ORF_T_PREFIX) type specific entry part.............*/
@@ -607,6 +619,12 @@ typedef U8 BGP_ORF_E_P_MAX_T ; /* Maxlen */
typedef U8 BGP_ORF_E_P_LEN_T ; /* Prefix Length */
typedef UBX BGP_ORF_E_P_PFIX_T ; /* Prefix -- variable ! */
+VALUE(BGP_ORF_E_P_MIN_L = BGP_ORF_E_COM_L
+ + sizeof(BGP_ORF_E_P_SEQ_T)
+ + sizeof(BGP_ORF_E_P_MIN_T)
+ + sizeof(BGP_ORF_E_P_MAX_T)
+ + sizeof(BGP_ORF_E_P_LEN_T) ) ;
+
/*==============================================================================
* Capability Values
*/
diff --git a/bgpd/bgp_common.h b/bgpd/bgp_common.h
index a5f66318..65f2476c 100644
--- a/bgpd/bgp_common.h
+++ b/bgpd/bgp_common.h
@@ -23,14 +23,20 @@
#define _QUAGGA_BGP_COMMON_H
#include <stdint.h>
+#include "bgpd/bgp.h"
#include "qafi_safi.h"
-#include "zassert.h"
+#include "confirm.h"
#ifndef Inline
#define Inline static inline
#endif
/*==============================================================================
+ * Local "bool"
+ */
+typedef uint8_t flag_t ;
+
+/*==============================================================================
* Here are a number of "incomplete" declarations, which allow a number of
* bgpd structures to refer to each other.
*/
@@ -115,16 +121,6 @@ enum bgp_session_events
typedef uint32_t as_t ;
typedef uint16_t as16_t ; /* we may still encounter 16 Bit asnums */
-/* BGP Identifier -- usually an IPv4 address ! */
-#ifndef _GMCH_BGP_H
-typedef uint32_t bgp_id_t ;
-#endif
-
-typedef bgp_id_t bgp_id_ht ; /* in host order */
-typedef bgp_id_t bgp_id_nt ; /* in network order */
-
-/* Size of BGP packets or thing in such */
-typedef uint16_t bgp_size_t;
/*==============================================================================
* AFI/SAFI encodings for bgpd
diff --git a/bgpd/bgp_connection.c b/bgpd/bgp_connection.c
index 35e76871..edfc19bc 100644
--- a/bgpd/bgp_connection.c
+++ b/bgpd/bgp_connection.c
@@ -20,7 +20,6 @@
*/
#include <zebra.h>
-#include "bgpd/bgp.h"
#include "bgpd/bgpd.h"
@@ -125,6 +124,8 @@ bgp_connection_init_new(bgp_connection connection, bgp_session session,
* * su_remote NULL -- no address, yet
* * hold_timer_interval none -- set when connection is opened
* * keepalive_timer_interval none -- set when connection is opened
+ * * as4 not AS4 conversation
+ * * route_refresh_pre not pre-RFC ROUTE-REFRESH
* * read_pending nothing pending
* * read_header not reading header
* * notification_pending nothing pending
@@ -160,8 +161,8 @@ bgp_connection_init_new(bgp_connection connection, bgp_session session,
bgp_connection_init_host(connection, bgp_connection_tags[ordinal]) ;
/* Need two empty "stream" buffers */
- connection->ibuf = stream_new(BGP_MAX_MSG_L) ;
- connection->obuf = stream_new(BGP_MAX_MSG_L) ;
+ connection->ibuf = stream_new(BGP_MSG_MAX_L) ;
+ connection->obuf = stream_new(BGP_MSG_MAX_L) ;
/* Ensure mqueue_local_queue is empty. */
mqueue_local_init_new(&connection->pending_queue) ;
@@ -238,7 +239,10 @@ bgp_connection_make_primary(bgp_connection connection)
bgp_connection_init_host(connection, "") ;
session->hold_timer_interval = connection->hold_timer_interval ;
- session->keepalive_timer_interval = session->keepalive_timer_interval ;
+ session->keepalive_timer_interval = connection->keepalive_timer_interval ;
+
+ session->as4 = connection->as4 ;
+ session->route_refresh_pre = connection->route_refresh_pre ;
session->su_local = connection->su_local ;
connection->su_local = NULL ;
@@ -284,24 +288,6 @@ bgp_connection_free(bgp_connection connection)
} ;
/*------------------------------------------------------------------------------
- * Full if not enough room for a maximum size BGP message.
- */
-static inline int
-bgp_write_buffer_full(bgp_wbuffer wb)
-{
- return ((wb->limit - wb->p_in) < BGP_MAX_MSG_L) ;
-} ;
-
-/*------------------------------------------------------------------------------
- * Empty if in and out pointers are equal (but may need to be reset !)
- */
-static inline int
-bgp_write_buffer_empty(bgp_wbuffer wb)
-{
- return (wb->p_out == wb->p_in) ;
-} ;
-
-/*------------------------------------------------------------------------------
* Allocate new write buffer and initialise pointers
*
* NB: assumes structure has been zeroised by the initialisation of the
@@ -316,9 +302,6 @@ bgp_write_buffer_init_new(bgp_wbuffer wb, size_t size)
wb->limit = wb->base + size ;
wb->p_in = wb->p_out = wb->base ;
- wb->full = bgp_write_buffer_full(wb) ;
-
- assert(!wb->full) ;
} ;
/*==============================================================================
@@ -565,7 +548,6 @@ bgp_connection_close(bgp_connection connection)
connection->wbuff.p_in = connection->wbuff.base ;
connection->wbuff.p_out = connection->wbuff.base ;
- connection->wbuff.full = 0 ;
/* Empty out the pending queue and remove from connection queue */
mqueue_local_reset_keep(&connection->pending_queue) ;
@@ -638,9 +620,6 @@ bgp_connection_part_close(bgp_connection connection)
else
wb->p_in = wb->p_out = wb->base ;
- wb->full = bgp_write_buffer_full(wb) ;
- assert(!wb->full) ;
-
/* Empty out the pending queue and remove from connection queue */
mqueue_local_reset_keep(&connection->pending_queue) ;
bgp_connection_queue_del(connection) ;
@@ -660,57 +639,72 @@ bgp_connection_part_close(bgp_connection connection)
* Returns true <=> able to write the entire buffer without blocking.
*/
-static int bgp_connection_write_direct(bgp_connection connection) ;
+static int bgp_connection_write_direct(bgp_connection connection,
+ struct stream* s) ;
static void bgp_connection_write_action(qps_file qf, void* file_info) ;
/*------------------------------------------------------------------------------
- * Write the contents of the obuf -- MUST not be here if wbuff is full !
+ * Write the contents of the given stream, if possible
*
- * Returns: 1 => all written -- obuf and wbuff are empty
- * 0 => written -- obuf now empty
- * -1 => failed -- error event generated
+ * Writes everything or nothing.
+ *
+ * If the write buffer is empty, then will attempt to write directly to the
+ * socket, buffering anything that cannot be sent immediately. Any errors
+ * encountered in this process generate an FSM event.
+ *
+ * In case it is relevant, identifies when the data has been written all the
+ * way into the TCP buffer.
+ *
+ * Returns: 2 => written to TCP -- it's gone -- stream reset, empty
+ * 1 => written to wbuff -- waiting for socket -- stream reset, empty
+ * 0 => nothing written -- insufficient space in wbuff
+ * -1 => failed -- error event generated
*/
extern int
-bgp_connection_write(bgp_connection connection)
+bgp_connection_write(bgp_connection connection, struct stream* s)
{
bgp_wbuffer wb = &connection->wbuff ;
if (bgp_write_buffer_empty(wb))
{
/* write buffer is empty -- attempt to write directly */
- return bgp_connection_write_direct(connection) ;
+ return bgp_connection_write_direct(connection, s) ;
} ;
- /* Transfer the obuf contents to the staging buffer. */
- wb->p_in = stream_transfer(wb->p_in, connection->obuf, wb->limit) ;
+ /* Write nothing if cannot write everything */
+ if (!bgp_write_buffer_can(wb, stream_pending(s)))
+ return 0 ;
+
+ /* Transfer the obuf contents to the write buffer. */
+ wb->p_in = stream_transfer(wb->p_in, s, wb->limit) ;
- return 1 ;
+ return 1 ; /* written as far as the write buffer */
} ;
/*------------------------------------------------------------------------------
- * The write buffer is empty -- so try to write obuf directly.
+ * The write buffer is empty -- so try to write stream directly.
*
- * If cannot empty the obuf directly to the TCP buffers, transfer it to to the
- * write buffer, and enable the qpselect action.
+ * If cannot empty the stream directly to the TCP buffers, transfer it to to
+ * the write buffer, and enable the qpselect action.
* (This is where the write buffer is allocated, if it hasn't yet been.)
*
- * Either way, the obuf is cleared and can be reused (unless failed).
+ * Either way, the stream is cleared and can be reused (unless failed).
*
- * Returns: 1 => written obuf to TCP buffer -- all buffers empty
- * 0 => written obuf to wbuff -- obuf empty
- * -1 => failed -- stopping, dead
+ * Returns: 2 => written to TCP -- it's gone -- stream reset, empty
+ * 1 => written to wbuff -- waiting for socket -- stream reset, empty
+ * -1 => failed -- error event generated
*/
-enum { bgp_wbuff_size = BGP_MAX_MSG_L * 10 } ;
+enum { bgp_wbuff_size = BGP_MSG_MAX_L * 10 } ;
static int
-bgp_connection_write_direct(bgp_connection connection)
+bgp_connection_write_direct(bgp_connection connection, struct stream* s)
{
int ret ;
- ret = stream_flush_try(connection->obuf, qps_file_fd(&connection->qf)) ;
+ ret = stream_flush_try(s, qps_file_fd(&connection->qf)) ;
if (ret == 0)
- return 1 ; /* Done: wbuff and obuf are empty */
+ return 2 ; /* Done: wbuff and stream are empty */
else if (ret > 0)
{
@@ -721,7 +715,7 @@ bgp_connection_write_direct(bgp_connection connection)
bgp_write_buffer_init_new(wb, bgp_wbuff_size) ;
/* Transfer *entire* message to staging buffer */
- wb->p_in = stream_transfer(wb->base, connection->obuf, wb->limit) ;
+ wb->p_in = stream_transfer(wb->base, s, wb->limit) ;
wb->p_out = wb->p_in - ret ; /* output from here */
@@ -729,7 +723,7 @@ bgp_connection_write_direct(bgp_connection connection)
qps_enable_mode(&connection->qf, qps_write_mnum,
bgp_connection_write_action) ;
- return 0 ; /* Done: obuf is empty, but wbuff is not */
+ return 1 ; /* Done: wbuff is not empty -- stream is */
} ;
/* write failed -- signal error and return failed */
@@ -782,7 +776,6 @@ bgp_connection_write_action(qps_file qf, void* file_info)
/* Buffer is empty -- reset it and disable write mode */
wb->p_out = wb->p_in = wb->base ;
- wb->full = 0 ;
qps_disable_modes(&connection->qf, qps_write_mbit) ;
@@ -824,7 +817,7 @@ bgp_connection_read_enable(bgp_connection connection)
* Performs the checks on the BGP message header:
*
* * Marker is all '1's
- * * Length is <= BGP_MAX_MSG_L
+ * * Length is <= BGP_MSG_MAX_L
* * Type is OPEN/UPDATE/NOTIFICATION/KEEPALIVE
*
*/
diff --git a/bgpd/bgp_connection.h b/bgpd/bgp_connection.h
index b4882a2f..f10eebbd 100644
--- a/bgpd/bgp_connection.h
+++ b/bgpd/bgp_connection.h
@@ -28,6 +28,9 @@
#include "lib/qpselect.h"
#include "lib/sockunion.h"
+#include "lib/stream.h"
+
+//#include "bgpd/bgp.h"
#include "bgpd/bgp_common.h"
#include "bgpd/bgp_session.h"
@@ -98,8 +101,6 @@ enum bgp_fsm_events
typedef struct bgp_wbuffer* bgp_wbuffer ;
struct bgp_wbuffer
{
- int full ; /* not enough room for max length BGP message */
-
uint8_t* p_out ;
uint8_t* p_in ;
@@ -148,6 +149,9 @@ struct bgp_connection
unsigned hold_timer_interval ; /* subject to negotiation */
unsigned keepalive_timer_interval ; /* subject to negotiation */
+ flag_t as4 ; /* subject to negotiation */
+ flag_t route_refresh_pre ; /* subject to negotiation */
+
struct qtimer hold_timer ;
struct qtimer keepalive_timer ;
@@ -200,7 +204,7 @@ extern void
bgp_connection_read_enable(bgp_connection connection) ;
extern int
-bgp_connection_write(bgp_connection connection) ;
+bgp_connection_write(bgp_connection connection, struct stream* s) ;
extern void
bgp_connection_queue_add(bgp_connection connection) ;
@@ -211,6 +215,52 @@ bgp_connection_queue_del(bgp_connection connection) ;
extern void
bgp_connection_queue_process(void) ;
+
+/*------------------------------------------------------------------------------
+ * Full if not enough room for a maximum size BGP message.
+ */
+Inline int
+bgp_write_buffer_can(bgp_wbuffer wb, size_t want)
+{
+ return ((size_t)(wb->limit - wb->p_in) <= want) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Full if not enough room for a maximum size BGP message + 1
+ */
+Inline int
+bgp_write_buffer_full(bgp_wbuffer wb)
+{
+ return bgp_write_buffer_can(wb, BGP_MAX_MSG_L + 1) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Empty if in and out pointers are equal (but may need to be reset !)
+ */
+Inline int
+bgp_write_buffer_empty(bgp_wbuffer wb)
+{
+ return (wb->p_out == wb->p_in) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * As above, for connection
+ */
+Inline int
+bgp_connection_write_full(bgp_connection connection)
+{
+ return bgp_write_buffer_full(&connection->wbuff) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * As above, for connection
+ */
+Inline int
+bgp_connection_write_empty(bgp_connection connection)
+{
+ return bgp_write_buffer_empty(&connection->wbuff) ;
+} ;
+
/*==============================================================================
* Access functions via bgp_connection for bgp_session attributes.
*
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index a5e3c58e..ccc16a7c 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -23,27 +23,22 @@
*/
#include <zebra.h>
-#include "bgpd/bgp.h"
+//#include "bgpd/bgp.h"
#include "log.h"
-#include "bgpd/bgp_engine.h"
#include "bgpd/bgp_session.h"
#include "bgpd/bgp_connection.h"
#include "bgpd/bgp_notification.h"
#include "bgpd/bgp_fsm.h"
+#include "bgpd/bgp_msg_write.h"
#include "lib/qtimers.h"
#include "lib/sockunion.h"
#include "bgpd/bgp_debug.h"
-#include "bgpd/bgp_packet.h"
#include "bgpd/bgp_network.h"
#include "bgpd/bgp_dump.h"
-#include "bgpd/bgp_open.h"
-#ifdef HAVE_SNMP
-#include "bgpd/bgp_snmp.h"
-#endif /* HAVE_SNMP */
/*==============================================================================
* The BGP Finite State Machine
@@ -1634,7 +1629,8 @@ static void
bgp_hold_timer_recharge(bgp_connection connection) ;
static bgp_fsm_state_t
-bgp_fsm_send_notification(bgp_connection connection, bgp_notify notification) ;
+bgp_fsm_send_notification(bgp_connection connection,
+ bgp_fsm_state_t next_state) ;
/*------------------------------------------------------------------------------
* Null action -- do nothing at all.
@@ -2124,8 +2120,7 @@ bgp_fsm_catch(bgp_connection connection, bgp_fsm_state_t next_state)
if ( (connection->notification != NULL)
&& (connection->except != bgp_session_eNOM_recv) )
{
- next_state = bgp_fsm_send_notification(connection,
- connection->notification) ;
+ next_state = bgp_fsm_send_notification(connection, next_state) ;
}
else
bgp_connection_close(connection) ;
@@ -2147,6 +2142,70 @@ bgp_fsm_catch(bgp_connection connection, bgp_fsm_state_t next_state)
return next_state ;
} ;
+/*------------------------------------------------------------------------------
+ * Dispatch notification message
+ *
+ * Part closing the connection guarantees that can get the notification
+ * message into the buffers.
+ *
+ * Process will generate the following events:
+ *
+ * -- I/O failure of any sort
+ * -- Sent_NOTIFICATION_message
+ * -- HoldTimer expired
+ *
+ * When get Sent_NOTIFICATION_message, will set final "courtesy" timer, so
+ * unless I/O fails, final end of process is HoldTimer expired (with
+ *
+ */
+static bgp_fsm_state_t
+bgp_fsm_send_notification(bgp_connection connection, bgp_fsm_state_t next_state)
+{
+ int ret ;
+
+ /* If the next_state is not Stopping, then the sending of the notification
+ * holds the FSM in the current state. Will move forward when the
+ * HoldTimer expires -- either because lost patience in getting the
+ * notification away, or at the end of the "courtesy" time.
+ */
+ if (next_state != bgp_fsm_Stopping)
+ next_state = connection->state ;
+
+ /* Close for reading and flush write buffers. */
+ bgp_connection_part_close(connection) ;
+
+ /* Write the message
+ *
+ * If the write fails it raises a suitable event, which will now be
+ * sitting waiting to be processed on the way out of the FSM.
+ */
+ ret = bgp_msg_write_notification(connection, connection->notification) ;
+
+ connection->notification_pending = (ret >= 0) ;
+ /* is pending if not failed */
+ if (ret > 0)
+ /* notification reached the TCP buffers instantly
+ *
+ * Send ourselves the good news !
+ */
+ bgp_fsm_event(connection, bgp_fsm_Sent_NOTIFICATION_message) ;
+
+ else if (ret == 0)
+ /* notification is sitting in the write buffer
+ *
+ * Set notification_pending so that write action will raise the required
+ * event in due course.
+ *
+ * Set the HoldTimer to something suitable. Don't really expect this
+ * to happen in anything except Established state -- but copes. (Is
+ * ready to wait 20 seconds in Stopping state and 5 otherwise.)
+ */
+ bgp_hold_timer_set(connection, (next_state == bgp_fsm_Stopping) ? 20 : 5) ;
+
+ /* Return suitable state. */
+ return next_state ;
+} ;
+
/*==============================================================================
* The BGP connections timers handling.
*
diff --git a/bgpd/bgp_msg_write.c b/bgpd/bgp_msg_write.c
index d15f1a26..fbc7ba0e 100644
--- a/bgpd/bgp_msg_write.c
+++ b/bgpd/bgp_msg_write.c
@@ -21,6 +21,11 @@
* Boston, MA 02111-1307, USA.
*/
+#include "bgpd/bgp_common.h"
+#include "bgpd/bgp_msg_write.h"
+#include "bgpd/bgp_route_refresh.h"
+
+
#include <zebra.h>
#include "thread.h"
@@ -54,2423 +59,794 @@
#include "bgpd/bgp_advertise.h"
#include "bgpd/bgp_vty.h"
-int stream_put_prefix (struct stream *, struct prefix *);
-
-/* Set up BGP packet marker and packet type. */
-static int
-bgp_packet_set_marker (struct stream *s, u_char type)
-{
- int i;
-
- /* Fill in marker. */
- for (i = 0; i < BGP_MARKER_SIZE; i++)
- stream_putc (s, 0xff);
-
- /* Dummy total length. This field is should be filled in later on. */
- stream_putw (s, 0);
-
- /* BGP packet type. */
- stream_putc (s, type);
-
- /* Return current stream size. */
- return stream_get_endp (s);
-}
-
-/* Set BGP packet header size entry. If size is zero then use current
- stream size. */
-static int
-bgp_packet_set_size (struct stream *s)
-{
- int cp;
-
- /* Preserve current pointer. */
- cp = stream_get_endp (s);
- stream_putw_at (s, BGP_MARKER_SIZE, cp);
+/*==============================================================================
+ * BGP Engine BGP Message encoding and sending.
+ *
+ *
+ */
- return cp;
-}
+/*==============================================================================
+ * NOTIFICATION and KEEPALIVE
+ */
-/* Add new packet to the peer. */
-static void
-bgp_packet_add (struct peer *peer, struct stream *s)
+/*------------------------------------------------------------------------------
+ * Make NOTIFICATION message and dispatch.
+ *
+ * NB: the write buffers will have been flushed -- so expect success !
+ *
+ * Returns: 2 => written to TCP -- it's gone
+ * 1 => written to wbuff -- waiting for socket
+ * 0 => nothing written -- wbuff was not empty !
+ * -1 => failed -- error event generated
+ */
+extern int
+bgp_msg_write_notification(bgp_connection connection, bgp_notify notification)
{
- /* Add packet to the end of list. */
- stream_fifo_push (peer->obuf, s);
-}
+ struct stream *s = connection->obuf ;
+ int length;
-/* Free first packet. */
-static void
-bgp_packet_delete (struct peer *peer)
-{
- stream_free (stream_fifo_pop (peer->obuf));
-}
+ assert(notification != NULL) ;
-/* Check file descriptor whether connect is established. */
-static void
-bgp_connect_check (struct peer *peer)
-{
- int status;
- socklen_t slen;
- int ret;
+ /* Make NOTIFY message header */
+ bgp_packet_set_marker (s, BGP_MSG_NOTIFY);
- /* Anyway I have to reset read and write thread. */
- BGP_READ_OFF (peer->t_read);
- BGP_WRITE_OFF (peer->t_write);
+ /* Set notify code and subcode */
+ stream_putc(s, bgp_notify_get_code(notification)) ;
+ stream_putc(s, bgp_notify_get_subcode(notification)) ;
- /* Check file descriptor. */
- slen = sizeof (status);
- ret = getsockopt(peer->fd, SOL_SOCKET, SO_ERROR, (void *) &status, &slen);
+ /* Copy the data portion, if any. */
+ length = bgp_notify_get_length(notification) ;
+ if (length != 0)
+ stream_write(s, bgp_notify_get_data(notification), length) ;
- /* If getsockopt is fail, this is fatal error. */
- if (ret < 0)
- {
- zlog (peer->log, LOG_INFO, "can't get sockopt for nonblocking connect");
- BGP_EVENT_ADD (peer, TCP_fatal_error);
- return;
- }
+ /* Set and get BGP packet length. */
+ length = bgp_packet_set_size(s);
- /* When status is 0 then TCP connection is established. */
- if (status == 0)
- {
- BGP_EVENT_ADD (peer, TCP_connection_open);
- }
- else
- {
- if (BGP_DEBUG (events, EVENTS))
- plog_debug (peer->log, "%s [Event] Connect failed (%s)",
- peer->host, safe_strerror (errno));
- BGP_EVENT_ADD (peer, TCP_connection_open_failed);
- }
-}
+ /* Logging */
+ if (BGP_DEBUG (normal, NORMAL))
+ zlog_debug("%s send message type %d, length (incl. header) %d",
+ connection->host, BGP_MSG_NOTIFY, length) ;
-/* Make BGP update packet. */
-static struct stream *
-bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi)
+ /* For debug */
+ {
+ bgp_notify text_form ;
+ const char* form ;
+ char c[4] ;
+ char* p ;
+
+ length = bgp_notify_get_length(notification) ;
+ p = bgp_notify_get_data(notification) ;
+
+ /* Make new copy of notification, with data portion large enough
+ * for the data rendered as hex characters.
+ */
+ text_form = bgp_notify_new(bgp_notify_get_code(notification),
+ bgp_notify_get_subcode(notification),
+ (length * 3)) ;
+ form = "%02x" ;
+ while (length--)
+ {
+ sprintf (c, form, *p++) ;
+ text_form = bgp_notify_append_data(text_form, c, strlen(c)) ;
+ form = " %02x" ;
+ } ;
+ text_form = bgp_notify_append_data(text_form, "\0", 1) ;
+
+ /* TODO: restore bgp_notify_print */
+#if 0
+ bgp_notify_print(peer, text_form, "sending") ;
+#endif
+ bgp_notify_free(&text_form) ;
+ } ;
+
+ /* Finally -- write the obuf away */
+ return bgp_connection_write(connection, s) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Make KEEPALIVE message and dispatch.
+ *
+ * NB: does nothing if the write buffer is not empty. This is not a problem,
+ * the KEEPALIVE is redundant if there is stuff waiting to go !
+ *
+ * KEEPALIVE is sent in response to OPEN, and that MUST be sent. But if the
+ * buffers are full at that point, something is broken !
+ *
+ * Returns: 2 => written to TCP -- it's gone
+ * 1 => written to wbuff -- waiting for socket
+ * 0 => nothing written -- wbuff was not empty !
+ * -1 => failed -- error event generated
+ */
+extern int
+bgp_msg_send_keepalive(bgp_connection connection)
{
- struct stream *s;
- struct bgp_adj_out *adj;
- struct bgp_advertise *adv;
- struct stream *packet;
- struct bgp_node *rn = NULL;
- struct bgp_info *binfo = NULL;
- bgp_size_t total_attr_len = 0;
- unsigned long pos;
- char buf[BUFSIZ];
-
- s = peer->work;
- stream_reset (s);
-
- adv = FIFO_HEAD (&peer->sync[afi][safi]->update);
-
- while (adv)
- {
- assert (adv->rn);
- rn = adv->rn;
- adj = adv->adj;
- if (adv->binfo)
- binfo = adv->binfo;
-
- /* When remaining space can't include NLRI and it's length. */
- if (STREAM_REMAIN (s) <= BGP_NLRI_LENGTH + PSIZE (rn->p.prefixlen))
- break;
-
- /* If packet is empty, set attribute. */
- if (stream_empty (s))
- {
- struct prefix_rd *prd = NULL;
- u_char *tag = NULL;
- struct peer *from = NULL;
-
- if (rn->prn)
- prd = (struct prefix_rd *) &rn->prn->p;
- if (binfo && binfo->extra)
- {
- tag = binfo->extra->tag;
- from = binfo->peer;
- }
-
- bgp_packet_set_marker (s, BGP_MSG_UPDATE);
- stream_putw (s, 0);
- pos = stream_get_endp (s);
- stream_putw (s, 0);
- total_attr_len = bgp_packet_attribute (NULL, peer, s,
- adv->baa->attr,
- &rn->p, afi, safi,
- from, prd, tag);
- stream_putw_at (s, pos, total_attr_len);
- }
-
- if (afi == AFI_IP && safi == SAFI_UNICAST)
- stream_put_prefix (s, &rn->p);
-
- if (BGP_DEBUG (update, UPDATE_OUT))
- zlog (peer->log, LOG_DEBUG, "%s send UPDATE %s/%d",
- peer->host,
- inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, BUFSIZ),
- rn->p.prefixlen);
-
- /* Synchnorize attribute. */
- if (adj->attr)
- bgp_attr_unintern (adj->attr);
- else
- peer->scount[afi][safi]++;
-
- adj->attr = bgp_attr_intern (adv->baa->attr);
-
- adv = bgp_advertise_clean (peer, adj, afi, safi);
-
- if (! (afi == AFI_IP && safi == SAFI_UNICAST))
- break;
- }
+ struct stream *s = connection->obuf ;
+ int length;
- if (! stream_empty (s))
- {
- bgp_packet_set_size (s);
- packet = stream_dup (s);
- bgp_packet_add (peer, packet);
- BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
- stream_reset (s);
- return packet;
- }
- return NULL;
-}
+ if (!bgp_connection_write_empty(connection))
+ return 0 ;
-static struct stream *
-bgp_update_packet_eor (struct peer *peer, afi_t afi, safi_t safi)
-{
- struct stream *s;
- struct stream *packet;
+ /* Make KEEPALIVE message -- comprises header only */
+ bgp_packet_set_marker(s, BGP_MSG_KEEPALIVE);
+ length = bgp_packet_set_size(s);
- if (DISABLE_BGP_ANNOUNCE)
- return NULL;
+ /* Dump packet if debug option is set. */
+ /* bgp_packet_dump (s); */
+ if (BGP_DEBUG (keepalive, KEEPALIVE))
+ zlog_debug ("%s sending KEEPALIVE", connection->host);
if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("send End-of-RIB for %s to %s", afi_safi_print (afi, safi), peer->host);
-
- s = stream_new (BGP_MAX_PACKET_SIZE);
+ zlog_debug ("%s send message type %d, length (incl. header) %d",
+ connection->host, BGP_MSG_KEEPALIVE, length);
- /* Make BGP update packet. */
- bgp_packet_set_marker (s, BGP_MSG_UPDATE);
+ /* Finally -- write the obuf away */
+ return bgp_connection_write(connection, s) ;
+} ;
- /* Unfeasible Routes Length */
- stream_putw (s, 0);
+/*==============================================================================
+ * OPEN message -- transform bgp_open_state into BGP message
+ */
- if (afi == AFI_IP && safi == SAFI_UNICAST)
- {
- /* Total Path Attribute Length */
- stream_putw (s, 0);
- }
- else
- {
- /* Total Path Attribute Length */
- stream_putw (s, 6);
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
- stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
- stream_putc (s, 3);
- stream_putw (s, afi);
- stream_putc (s, safi);
- }
+static void
+bgp_open_options(struct stream *s, bgp_open_state open_state) ;
- bgp_packet_set_size (s);
- packet = stream_dup (s);
- bgp_packet_add (peer, packet);
- stream_free (s);
- return packet;
-}
+static void
+bgp_open_capability_orf (struct stream *s, iAFI_t afi, iSAFI_t safi,
+ u_char cap_code, u_char orf_type, u_char mode) ;
-/* Make BGP withdraw packet. */
-static struct stream *
-bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi)
+/*------------------------------------------------------------------------------
+ * Make OPEN message and dispatch.
+ *
+ * OPEN is the first message to be sent. If the buffers are not empty,
+ * something is badly wrong !
+ *
+ * Returns: 2 => written to TCP -- it's gone
+ * 1 => written to wbuff -- waiting for socket
+ * 0 => nothing written -- wbuff was too full !!!
+ * -1 => failed -- error event generated
+ */
+extern int
+bgp_msg_send_open(bgp_connection connection, bgp_open_state open_state)
{
- struct stream *s;
- struct stream *packet;
- struct bgp_adj_out *adj;
- struct bgp_advertise *adv;
- struct bgp_node *rn;
- unsigned long pos;
- bgp_size_t unfeasible_len;
- bgp_size_t total_attr_len;
- char buf[BUFSIZ];
-
- s = peer->work;
- stream_reset (s);
-
- while ((adv = FIFO_HEAD (&peer->sync[afi][safi]->withdraw)) != NULL)
- {
- assert (adv->rn);
- adj = adv->adj;
- rn = adv->rn;
-
- if (STREAM_REMAIN (s)
- < (BGP_NLRI_LENGTH + BGP_TOTAL_ATTR_LEN + PSIZE (rn->p.prefixlen)))
- break;
-
- if (stream_empty (s))
- {
- bgp_packet_set_marker (s, BGP_MSG_UPDATE);
- stream_putw (s, 0);
- }
-
- if (afi == AFI_IP && safi == SAFI_UNICAST)
- stream_put_prefix (s, &rn->p);
- else
- {
- struct prefix_rd *prd = NULL;
-
- if (rn->prn)
- prd = (struct prefix_rd *) &rn->prn->p;
- pos = stream_get_endp (s);
- stream_putw (s, 0);
- total_attr_len
- = bgp_packet_withdraw (peer, s, &rn->p, afi, safi, prd, NULL);
+ struct stream *s = connection->obuf ;
+ int length ;
- /* Set total path attribute length. */
- stream_putw_at (s, pos, total_attr_len);
- }
+ assert(bgp_connection_write_empty(connection)) ;
- if (BGP_DEBUG (update, UPDATE_OUT))
- zlog (peer->log, LOG_DEBUG, "%s send UPDATE %s/%d -- unreachable",
- peer->host,
- inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, BUFSIZ),
- rn->p.prefixlen);
-
- peer->scount[afi][safi]--;
-
- bgp_adj_out_remove (rn, adj, peer, afi, safi);
- bgp_unlock_node (rn);
-
- if (! (afi == AFI_IP && safi == SAFI_UNICAST))
- break;
- }
-
- if (! stream_empty (s))
- {
- if (afi == AFI_IP && safi == SAFI_UNICAST)
- {
- unfeasible_len
- = stream_get_endp (s) - BGP_HEADER_SIZE - BGP_UNFEASIBLE_LEN;
- stream_putw_at (s, BGP_HEADER_SIZE, unfeasible_len);
- stream_putw (s, 0);
- }
- bgp_packet_set_size (s);
- packet = stream_dup (s);
- bgp_packet_add (peer, packet);
- stream_reset (s);
- return packet;
- }
+ /* Make OPEN message header */
+ bgp_packet_set_marker(s, BGP_MSG_OPEN) ;
- return NULL;
-}
+ /* Set OPEN message fixed part */
+ stream_putc(s, BGP_VERSION_4) ;
+ stream_putw(s, (open_state->my_as <= BGP_AS_MAX)
+ ? (u_int16_t) open_state->my_as : BGP_AS_TRANS) ;
+ stream_putw(s, open_state->holdtime) ;
+ stream_putl(s, open_state->bgp_id) ;
-void
-bgp_default_update_send (struct peer *peer, struct attr *attr,
- afi_t afi, safi_t safi, struct peer *from)
-{
- struct stream *s;
- struct stream *packet;
- struct prefix p;
- unsigned long pos;
- bgp_size_t total_attr_len;
- char attrstr[BUFSIZ];
- char buf[BUFSIZ];
-
- if (DISABLE_BGP_ANNOUNCE)
- return;
+ /* Set OPEN message options */
+ bgp_open_options(s, open_state) ;
- if (afi == AFI_IP)
- str2prefix ("0.0.0.0/0", &p);
-#ifdef HAVE_IPV6
- else
- str2prefix ("::/0", &p);
-#endif /* HAVE_IPV6 */
+ /* Set BGP message length. */
+ length = bgp_packet_set_size(s) ;
- /* Logging the attribute. */
- if (BGP_DEBUG (update, UPDATE_OUT))
+ if (BGP_DEBUG (normal, NORMAL))
{
- bgp_dump_attr (peer, attr, attrstr, BUFSIZ);
- zlog (peer->log, LOG_DEBUG, "%s send UPDATE %s/%d %s",
- peer->host, inet_ntop(p.family, &(p.u.prefix), buf, BUFSIZ),
- p.prefixlen, attrstr);
- }
-
- s = stream_new (BGP_MAX_PACKET_SIZE);
-
- /* Make BGP update packet. */
- bgp_packet_set_marker (s, BGP_MSG_UPDATE);
+ struct in_addr bgp_id ;
+ char buf[INET_ADDRSTRLEN] ;
- /* Unfeasible Routes Length. */
- stream_putw (s, 0);
+ bgp_id.s_addr = htonl(open_state->bgp_id) ;
+ inet_ntop(AF_INET, &bgp_id.s_addr, buf, INET_ADDRSTRLEN) ;
- /* Make place for total attribute length. */
- pos = stream_get_endp (s);
- stream_putw (s, 0);
- total_attr_len = bgp_packet_attribute (NULL, peer, s, attr, &p, afi, safi, from, NULL, NULL);
+ zlog_debug ("%s sending OPEN, version %d, my as %u, holdtime %d, id %s",
+ connection->host, BGP_VERSION_4, open_state->my_as,
+ open_state->holdtime, buf) ;
- /* Set Total Path Attribute Length. */
- stream_putw_at (s, pos, total_attr_len);
+ } ;
- /* NLRI set. */
- if (p.family == AF_INET && safi == SAFI_UNICAST)
- stream_put_prefix (s, &p);
-
- /* Set size. */
- bgp_packet_set_size (s);
-
- packet = stream_dup (s);
- stream_free (s);
+ if (BGP_DEBUG (normal, NORMAL))
+ zlog_debug ("%s send message type %d, length (incl. header) %d",
+ connection->host, BGP_MSG_OPEN, length);
/* Dump packet if debug option is set. */
-#ifdef DEBUG
- /* bgp_packet_dump (packet); */
-#endif /* DEBUG */
-
- /* Add packet to the peer. */
- bgp_packet_add (peer, packet);
+ /* bgp_packet_dump (s); */
- BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
+ /* Finally -- write the obuf away */
+ return bgp_connection_write(connection, s) ;
}
-void
-bgp_default_withdraw_send (struct peer *peer, afi_t afi, safi_t safi)
+enum
{
- struct stream *s;
- struct stream *packet;
- struct prefix p;
- unsigned long pos;
- unsigned long cp;
- bgp_size_t unfeasible_len;
- bgp_size_t total_attr_len;
- char buf[BUFSIZ];
-
- if (DISABLE_BGP_ANNOUNCE)
- return;
-
- if (afi == AFI_IP)
- str2prefix ("0.0.0.0/0", &p);
+ have_ipv6 =
#ifdef HAVE_IPV6
- else
- str2prefix ("::/0", &p);
-#endif /* HAVE_IPV6 */
-
- total_attr_len = 0;
- pos = 0;
-
- if (BGP_DEBUG (update, UPDATE_OUT))
- zlog (peer->log, LOG_DEBUG, "%s send UPDATE %s/%d -- unreachable",
- peer->host, inet_ntop(p.family, &(p.u.prefix), buf, BUFSIZ),
- p.prefixlen);
-
- s = stream_new (BGP_MAX_PACKET_SIZE);
-
- /* Make BGP update packet. */
- bgp_packet_set_marker (s, BGP_MSG_UPDATE);
+ 1
+#else
+ 0
+#endif
+} ;
+
+/*------------------------------------------------------------------------------
+ * Add options to given encoded OPEN message.
+ *
+ * Supports the status quo: only Capability Options.
+ *
+ * Creates an empty options part of there are no capabilities to set.
+ */
+static void
+bgp_open_options(struct stream *s, bgp_open_state open_state)
+{
+ u_char len ;
+ unsigned long cp ;
+ qafx_num_t qafx ;
- /* Unfeasible Routes Length. */;
+ /* Remember current pointer for Opt Parm Len. */
cp = stream_get_endp (s);
- stream_putw (s, 0);
- /* Withdrawn Routes. */
- if (p.family == AF_INET && safi == SAFI_UNICAST)
- {
- stream_put_prefix (s, &p);
+ /* Opt Parm Len. */
+ stream_putc(s, 0);
- unfeasible_len = stream_get_endp (s) - cp - 2;
+ /* If do not send capability, quit now -- zero options. */
+ if (!open_state->can_capability)
+ return;
- /* Set unfeasible len. */
- stream_putw_at (s, cp, unfeasible_len);
+ /* TODO: RFC 5492 (2009): SHOULD send only one Capability Option !! */
+ /* RFC 3392 (2002): silent on the matter */
+ /* RFC 2842 (2000): silent on the matter */
- /* Set total path attribute length. */
- stream_putw (s, 0);
- }
- else
+ /* Send capability for every AFI/SAFI supported. */
+ for (qafx = qafx_num_first ; qafx <= qafx_num_last ; ++qafx)
{
- pos = stream_get_endp (s);
- stream_putw (s, 0);
- total_attr_len = bgp_packet_withdraw (peer, s, &p, afi, safi, NULL, NULL);
-
- /* Set total path attribute length. */
- stream_putw_at (s, pos, total_attr_len);
- }
-
- bgp_packet_set_size (s);
-
- packet = stream_dup (s);
- stream_free (s);
-
- /* Add packet to the peer. */
- bgp_packet_add (peer, packet);
-
- BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
-}
-
-/* Get next packet to be written. */
-static struct stream *
-bgp_write_packet (struct peer *peer)
-{
- afi_t afi;
- safi_t safi;
- struct stream *s = NULL;
- struct bgp_advertise *adv;
-
- s = stream_fifo_head (peer->obuf);
- if (s)
- return s;
-
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- {
- adv = FIFO_HEAD (&peer->sync[afi][safi]->withdraw);
- if (adv)
- {
- s = bgp_withdraw_packet (peer, afi, safi);
- if (s)
- return s;
- }
- }
-
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- {
- adv = FIFO_HEAD (&peer->sync[afi][safi]->update);
- if (adv)
- {
- if (adv->binfo && adv->binfo->uptime < peer->synctime)
- {
- if (CHECK_FLAG (adv->binfo->peer->cap, PEER_CAP_RESTART_RCV)
- && CHECK_FLAG (adv->binfo->peer->cap, PEER_CAP_RESTART_ADV)
- && ! CHECK_FLAG (adv->binfo->flags, BGP_INFO_STALE)
- && safi != SAFI_MPLS_VPN)
- {
- if (CHECK_FLAG (adv->binfo->peer->af_sflags[afi][safi],
- PEER_STATUS_EOR_RECEIVED))
- s = bgp_update_packet (peer, afi, safi);
- }
- else
- s = bgp_update_packet (peer, afi, safi);
- }
-
- if (s)
- return s;
- }
-
- if (CHECK_FLAG (peer->cap, PEER_CAP_RESTART_RCV))
- {
- if (peer->afc_nego[afi][safi] && peer->synctime
- && ! CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_EOR_SEND)
- && safi != SAFI_MPLS_VPN)
- {
- SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_EOR_SEND);
- return bgp_update_packet_eor (peer, afi, safi);
- }
- }
- }
-
- return NULL;
-}
-
-/* Is there partially written packet or updates we can send right
- now. */
-static int
-bgp_write_proceed (struct peer *peer)
-{
- afi_t afi;
- safi_t safi;
- struct bgp_advertise *adv;
-
- if (stream_fifo_head (peer->obuf))
- return 1;
+ if (open_state->can_mp_ext & qafx_bit(qafx))
+ {
+ iAFI_t afi = get_iAFI(qafx) ;
+ iSAFI_t safi = get_iSAFI(qafx) ;
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- if (FIFO_HEAD (&peer->sync[afi][safi]->withdraw))
- return 1;
+ if (!have_ipv6 && (afi == iAFI_IP6))
+ continue ;
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- if ((adv = FIFO_HEAD (&peer->sync[afi][safi]->update)) != NULL)
- if (adv->binfo->uptime < peer->synctime)
- return 1;
+ stream_putc (s, BGP_OPEN_OPT_CAP);
+ stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
+ stream_putc (s, CAPABILITY_CODE_MP);
+ stream_putc (s, CAPABILITY_CODE_MP_LEN);
+ stream_putw (s, afi);
+ stream_putc (s, 0);
+ stream_putc (s, safi);
+ } ;
+ } ;
- return 0;
-}
+ /* Route refresh. */
-/* Write packet to the peer. */
-int
-bgp_write (struct thread *thread)
-{
- struct peer *peer;
- u_char type;
- struct stream *s;
- int num;
- unsigned int count = 0;
- int write_errno;
-
- /* Yes first of all get peer pointer. */
- peer = THREAD_ARG (thread);
- peer->t_write = NULL;
-
- /* For non-blocking IO check. */
- if (peer->status == Connect)
+ if (open_state->can_r_refresh & bgp_cap_form_old)
{
- bgp_connect_check (peer);
- return 0;
- }
+ stream_putc (s, BGP_OPEN_OPT_CAP) ;
+ stream_putc (s, CAPABILITY_CODE_REFRESH_LEN + 2) ;
+ stream_putc (s, CAPABILITY_CODE_REFRESH_OLD) ;
+ stream_putc (s, CAPABILITY_CODE_REFRESH_LEN) ;
+ } ;
- /* Nonblocking write until TCP output buffer is full. */
- while (1)
+ if (open_state->can_r_refresh & bgp_cap_form_old)
{
- int writenum;
- int val;
+ stream_putc (s, BGP_OPEN_OPT_CAP) ;
+ stream_putc (s, CAPABILITY_CODE_REFRESH_LEN + 2) ;
+ stream_putc (s, CAPABILITY_CODE_REFRESH) ;
+ stream_putc (s, CAPABILITY_CODE_REFRESH_LEN) ;
+ } ;
- s = bgp_write_packet (peer);
- if (! s)
- return 0;
+ /* AS4 */
- /* 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)
- {
- /* Partial write. */
- if (write_errno == EWOULDBLOCK || write_errno == EAGAIN)
- break;
-
- BGP_EVENT_ADD (peer, TCP_fatal_error);
- return 0;
- }
- if (num != writenum)
- {
- stream_forward_getp (s, num);
-
- if (write_errno == EAGAIN)
- break;
-
- continue;
- }
-
- /* Retrieve BGP packet type. */
- stream_set_getp (s, BGP_MARKER_SIZE + 2);
- type = stream_getc (s);
-
- switch (type)
- {
- case BGP_MSG_OPEN:
- peer->open_out++;
- break;
- case BGP_MSG_UPDATE:
- peer->update_out++;
- break;
- case BGP_MSG_NOTIFY:
- peer->notify_out++;
- /* Double start timer. */
- peer->v_start *= 2;
-
- /* Overflow check. */
- if (peer->v_start >= (60 * 2))
- peer->v_start = (60 * 2);
-
- /* Flush any existing events */
- BGP_EVENT_ADD (peer, BGP_Stop);
- return 0;
- case BGP_MSG_KEEPALIVE:
- peer->keepalive_out++;
- break;
- case BGP_MSG_ROUTE_REFRESH_NEW:
- case BGP_MSG_ROUTE_REFRESH_OLD:
- peer->refresh_out++;
- break;
- case BGP_MSG_CAPABILITY:
- peer->dynamic_cap_out++;
- break;
- }
-
- /* OK we send packet so delete it. */
- bgp_packet_delete (peer);
-
- if (++count >= BGP_WRITE_PACKET_MAX)
- break;
- }
-
- if (bgp_write_proceed (peer))
- BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
-
- return 0;
-}
-
-/* This is only for sending NOTIFICATION message to neighbor. */
-static int
-bgp_write_notify (struct peer *peer)
-{
- int ret;
- u_char type;
- struct stream *s;
-
- /* There should be at least one packet. */
- s = stream_fifo_head (peer->obuf);
- if (!s)
- return 0;
- assert (stream_get_endp (s) >= BGP_HEADER_SIZE);
-
- /* I'm not sure fd is writable. */
- ret = writen (peer->fd, STREAM_DATA (s), stream_get_endp (s));
- if (ret <= 0)
+ if (open_state->can_as4)
{
- BGP_EVENT_ADD (peer, TCP_fatal_error);
- return 0;
- }
-
- /* Retrieve BGP packet type. */
- stream_set_getp (s, BGP_MARKER_SIZE + 2);
- type = stream_getc (s);
-
- assert (type == BGP_MSG_NOTIFY);
-
- /* Type should be notify. */
- peer->notify_out++;
-
- /* Double start timer. */
- peer->v_start *= 2;
-
- /* Overflow check. */
- if (peer->v_start >= (60 * 2))
- peer->v_start = (60 * 2);
-
- BGP_EVENT_ADD (peer, BGP_Stop);
-
- return 0;
-}
-
-/* Make keepalive packet and send it to the peer. */
-void
-bgp_keepalive_send (struct peer *peer)
-{
- struct stream *s;
- int length;
-
- s = stream_new (BGP_MAX_PACKET_SIZE);
-
- /* Make keepalive packet. */
- bgp_packet_set_marker (s, BGP_MSG_KEEPALIVE);
-
- /* Set packet size. */
- length = bgp_packet_set_size (s);
-
- /* Dump packet if debug option is set. */
- /* bgp_packet_dump (s); */
-
- if (BGP_DEBUG (keepalive, KEEPALIVE))
- zlog_debug ("%s sending KEEPALIVE", peer->host);
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s send message type %d, length (incl. header) %d",
- peer->host, BGP_MSG_KEEPALIVE, length);
-
- /* Add packet to the peer. */
- bgp_packet_add (peer, s);
-
- BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
-}
-
-/* Make open packet and send it to the peer. */
-void
-bgp_open_send (struct peer *peer)
-{
- struct stream *s;
- int length;
- u_int16_t send_holdtime;
- as_t local_as;
-
- if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER))
- send_holdtime = peer->holdtime;
- else
- send_holdtime = peer->bgp->default_holdtime;
-
- /* local-as Change */
- if (peer->change_local_as)
- local_as = peer->change_local_as;
- else
- local_as = peer->local_as;
+ stream_putc (s, BGP_OPEN_OPT_CAP);
+ stream_putc (s, CAPABILITY_CODE_AS4_LEN + 2);
+ stream_putc (s, CAPABILITY_CODE_AS4);
+ stream_putc (s, CAPABILITY_CODE_AS4_LEN);
+ stream_putl (s, open_state->my_as) ;
+ } ;
- s = stream_new (BGP_MAX_PACKET_SIZE);
+ /* ORF Capabilities */
- /* Make open packet. */
- bgp_packet_set_marker (s, BGP_MSG_OPEN);
-
- /* Set open packet values. */
- stream_putc (s, BGP_VERSION_4); /* BGP version */
- stream_putw (s, (local_as <= BGP_AS_MAX) ? (u_int16_t) local_as
- : BGP_AS_TRANS);
- stream_putw (s, send_holdtime); /* Hold Time */
- stream_put_in_addr (s, &peer->local_id); /* BGP Identifier */
-
- /* Set capability code. */
- bgp_open_capability (s, peer);
-
- /* Set BGP packet length. */
- length = bgp_packet_set_size (s);
-
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s sending OPEN, version %d, my as %u, holdtime %d, id %s",
- peer->host, BGP_VERSION_4, local_as,
- send_holdtime, inet_ntoa (peer->local_id));
-
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s send message type %d, length (incl. header) %d",
- peer->host, BGP_MSG_OPEN, length);
-
- /* Dump packet if debug option is set. */
- /* bgp_packet_dump (s); */
-
- /* Add packet to the peer. */
- bgp_packet_add (peer, s);
-
- BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
-}
-
-/* Send BGP notify packet with data potion. */
-void
-bgp_notify_send_with_data (struct peer *peer, u_char code, u_char sub_code,
- u_char *data, size_t datalen)
-{
- struct stream *s;
- int length;
-
- /* Allocate new stream. */
- s = stream_new (BGP_MAX_PACKET_SIZE);
-
- /* Make nitify packet. */
- bgp_packet_set_marker (s, BGP_MSG_NOTIFY);
-
- /* Set notify packet values. */
- stream_putc (s, code); /* BGP notify code */
- stream_putc (s, sub_code); /* BGP notify sub_code */
-
- /* If notify data is present. */
- if (data)
- stream_write (s, data, datalen);
-
- /* Set BGP packet length. */
- length = bgp_packet_set_size (s);
-
- /* Add packet to the peer. */
- stream_fifo_clean (peer->obuf);
- bgp_packet_add (peer, s);
-
- /* For debug */
- {
- struct bgp_notify bgp_notify;
- int first = 0;
- int i;
- char c[4];
-
- bgp_notify.code = code;
- bgp_notify.subcode = sub_code;
- bgp_notify.data = NULL;
- bgp_notify.length = length - BGP_MSG_NOTIFY_MIN_SIZE;
-
- if (bgp_notify.length)
- {
- bgp_notify.data = XMALLOC (MTYPE_TMP, bgp_notify.length * 3);
- for (i = 0; i < bgp_notify.length; i++)
- if (first)
- {
- sprintf (c, " %02x", data[i]);
- strcat (bgp_notify.data, c);
- }
- else
- {
- first = 1;
- sprintf (c, "%02x", data[i]);
- strcpy (bgp_notify.data, c);
- }
- }
- bgp_notify_print (peer, &bgp_notify, "sending");
- if (bgp_notify.data)
- XFREE (MTYPE_TMP, bgp_notify.data);
- }
-
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s send message type %d, length (incl. header) %d",
- peer->host, BGP_MSG_NOTIFY, length);
-
- /* peer reset cause */
- if (sub_code != BGP_NOTIFY_CEASE_CONFIG_CHANGE)
+ for (qafx = qafx_num_first ; qafx <= qafx_num_last ; ++qafx)
{
- if (sub_code == BGP_NOTIFY_CEASE_ADMIN_RESET)
- peer->last_reset = PEER_DOWN_USER_RESET;
- else if (sub_code == BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN)
- peer->last_reset = PEER_DOWN_USER_SHUTDOWN;
- else
- peer->last_reset = PEER_DOWN_NOTIFY_SEND;
- }
+ u_char mode = 0 ;
- /* Call imidiately. */
- BGP_WRITE_OFF (peer->t_write);
+ if (open_state->can_orf_prefix_send & qafx_bit(qafx))
+ mode |= ORF_MODE_SEND ;
+ if (open_state->can_orf_prefix_recv & qafx_bit(qafx))
+ mode |= ORF_MODE_RECEIVE ;
- bgp_write_notify (peer);
-}
+ confirm((ORF_MODE_SEND | ORF_MODE_RECEIVE) == ORF_MODE_BOTH) ;
-/* Send BGP notify packet. */
-void
-bgp_notify_send (struct peer *peer, u_char code, u_char sub_code)
+ if (mode != 0)
+ {
+ iAFI_t afi = get_iAFI(qafx) ;
+ iSAFI_t safi = get_iSAFI(qafx) ;
+
+ if (!have_ipv6 && (afi == iAFI_IP6))
+ continue ;
+
+ if (open_state->can_orf_prefix & bgp_cap_form_old)
+ bgp_open_capability_orf(s, afi, safi, CAPABILITY_CODE_ORF_OLD,
+ ORF_TYPE_PREFIX_OLD, mode) ;
+
+ if (open_state->can_orf_prefix & bgp_cap_form_new)
+ bgp_open_capability_orf(s, afi, safi, CAPABILITY_CODE_ORF,
+ ORF_TYPE_PREFIX, mode) ;
+ } ;
+ } ;
+
+ /* Dynamic capability. */
+ if (open_state->can_dynamic)
+ {
+ stream_putc (s, BGP_OPEN_OPT_CAP);
+ stream_putc (s, CAPABILITY_CODE_DYNAMIC_LEN + 2);
+ stream_putc (s, CAPABILITY_CODE_DYNAMIC);
+ stream_putc (s, CAPABILITY_CODE_DYNAMIC_LEN);
+ } ;
+
+ /* Graceful restart capability */
+ if (open_state->can_g_restart)
+ {
+ stream_putc (s, BGP_OPEN_OPT_CAP);
+ stream_putc (s, CAPABILITY_CODE_RESTART_LEN + 2);
+ stream_putc (s, CAPABILITY_CODE_RESTART);
+ stream_putc (s, CAPABILITY_CODE_RESTART_LEN);
+ stream_putw (s, open_state->restart_time);
+ } ;
+
+ /* TODO: restarting flag ?? */
+ /* TODO: graceful restart preserving forwarding state */
+
+ /* Total Opt Parm Len. */
+ len = stream_get_endp (s) - cp - 1;
+ stream_putc_at (s, cp, len);
+} ;
+
+/*------------------------------------------------------------------------------
+ * Add an ORF capability to the given encoded OPEN message.
+ *
+ * Supports the status quo: only prefix-list filtering !
+ */
+static void
+bgp_open_capability_orf (struct stream *s, iAFI_t afi, iSAFI_t safi,
+ u_char cap_code, u_char orf_type, u_char mode)
{
- bgp_notify_send_with_data (peer, code, sub_code, NULL, 0);
-}
+ u_char cap_len;
+ u_char orf_len;
+ unsigned long capp;
+ unsigned long orfp;
+ unsigned long numberp;
-/* Send route refresh message to the peer. */
-void
-bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi,
- u_char orf_type, u_char when_to_refresh, int remove)
-{
- struct stream *s;
- struct stream *packet;
- int length;
- struct bgp_filter *filter;
- int orf_refresh = 0;
+ int number_of_orfs = 0;
- if (DISABLE_BGP_ANNOUNCE)
- return;
+ stream_putc (s, BGP_OPEN_OPT_CAP);
+ capp = stream_get_endp (s); /* Set Capability Len Pointer */
+ stream_putc (s, 0); /* Capability Length */
+ stream_putc (s, cap_code); /* Capability Code */
+ orfp = stream_get_endp (s); /* Set ORF Len Pointer */
+ stream_putc (s, 0); /* ORF Length */
- filter = &peer->filter[afi][safi];
-
- /* Adjust safi code. */
- if (safi == SAFI_MPLS_VPN)
- safi = BGP_SAFI_VPNV4;
-
- s = stream_new (BGP_MAX_PACKET_SIZE);
-
- /* Make BGP update packet. */
- if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV))
- bgp_packet_set_marker (s, BGP_MSG_ROUTE_REFRESH_NEW);
- else
- bgp_packet_set_marker (s, BGP_MSG_ROUTE_REFRESH_OLD);
-
- /* Encode Route Refresh message. */
stream_putw (s, afi);
stream_putc (s, 0);
stream_putc (s, safi);
- if (orf_type == ORF_TYPE_PREFIX
- || orf_type == ORF_TYPE_PREFIX_OLD)
- if (remove || filter->plist[FILTER_IN].ref)
- {
- u_int16_t orf_len;
- unsigned long orfp;
-
- orf_refresh = 1;
- stream_putc (s, when_to_refresh);
- stream_putc (s, orf_type);
- orfp = stream_get_endp (s);
- stream_putw (s, 0);
-
- if (remove)
- {
- UNSET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND);
- stream_putc (s, ORF_COMMON_PART_REMOVE_ALL);
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s sending REFRESH_REQ to remove ORF(%d) (%s) for afi/safi: %d/%d",
- peer->host, orf_type,
- (when_to_refresh == REFRESH_DEFER ? "defer" : "immediate"),
- afi, safi);
- }
- else
- {
- SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND);
- prefix_bgp_orf_entry (s, filter->plist[FILTER_IN].ref,
- ORF_COMMON_PART_ADD, ORF_COMMON_PART_PERMIT,
- ORF_COMMON_PART_DENY);
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s sending REFRESH_REQ with pfxlist ORF(%d) (%s) for afi/safi: %d/%d",
- peer->host, orf_type,
- (when_to_refresh == REFRESH_DEFER ? "defer" : "immediate"),
- afi, safi);
- }
-
- /* Total ORF Entry Len. */
- orf_len = stream_get_endp (s) - orfp - 2;
- stream_putw_at (s, orfp, orf_len);
- }
-
- /* Set packet size. */
- length = bgp_packet_set_size (s);
-
- if (BGP_DEBUG (normal, NORMAL))
- {
- if (! orf_refresh)
- zlog_debug ("%s sending REFRESH_REQ for afi/safi: %d/%d",
- peer->host, afi, safi);
- zlog_debug ("%s send message type %d, length (incl. header) %d",
- peer->host, CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV) ?
- BGP_MSG_ROUTE_REFRESH_NEW : BGP_MSG_ROUTE_REFRESH_OLD, length);
- }
-
- /* Make real packet. */
- packet = stream_dup (s);
- stream_free (s);
-
- /* Add packet to the peer. */
- bgp_packet_add (peer, packet);
-
- BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
-}
-
-/* Send capability message to the peer. */
-void
-bgp_capability_send (struct peer *peer, afi_t afi, safi_t safi,
- int capability_code, int action)
-{
- struct stream *s;
- struct stream *packet;
- int length;
-
- /* Adjust safi code. */
- if (safi == SAFI_MPLS_VPN)
- safi = BGP_SAFI_VPNV4;
+ numberp = stream_get_endp (s); /* Set Number Pointer */
+ stream_putc (s, 0); /* Number of ORFs */
- s = stream_new (BGP_MAX_PACKET_SIZE);
+ /* Address Prefix ORF */
+ stream_putc (s, orf_type) ; /* type of ORF */
+ stream_putc (s, mode) ;
- /* Make BGP update packet. */
- bgp_packet_set_marker (s, BGP_MSG_CAPABILITY);
+ number_of_orfs++;
- /* Encode MP_EXT capability. */
- if (capability_code == CAPABILITY_CODE_MP)
- {
- stream_putc (s, action);
- stream_putc (s, CAPABILITY_CODE_MP);
- stream_putc (s, CAPABILITY_CODE_MP_LEN);
- stream_putw (s, afi);
- stream_putc (s, 0);
- stream_putc (s, safi);
-
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s sending CAPABILITY has %s MP_EXT CAP for afi/safi: %d/%d",
- peer->host, action == CAPABILITY_ACTION_SET ?
- "Advertising" : "Removing", afi, safi);
- }
+ /* Total Number of ORFs. */
+ stream_putc_at (s, numberp, number_of_orfs);
- /* Set packet size. */
- length = bgp_packet_set_size (s);
+ /* Total ORF Len. */
+ orf_len = stream_get_endp (s) - orfp - 1;
+ stream_putc_at (s, orfp, orf_len);
- /* Make real packet. */
- packet = stream_dup (s);
- stream_free (s);
+ /* Total Capability Len. */
+ cap_len = stream_get_endp (s) - capp - 1;
+ stream_putc_at (s, capp, cap_len);
+} ;
- /* Add packet to the peer. */
- bgp_packet_add (peer, packet);
-
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s send message type %d, length (incl. header) %d",
- peer->host, BGP_MSG_CAPABILITY, length);
-
- BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
-}
+/*==============================================================================
+ * ROUTE-REFRESH -- transform bgp_prefix_orf_update into BGP message
+ */
-/* RFC1771 6.8 Connection collision detection. */
static int
-bgp_collision_detect (struct peer *new, struct in_addr remote_id)
-{
- struct peer *peer;
- struct listnode *node, *nnode;
- struct bgp *bgp;
-
- bgp = bgp_get_default ();
- if (! bgp)
- return 0;
-
- /* Upon receipt of an OPEN message, the local system must examine
- all of its connections that are in the OpenConfirm state. A BGP
- speaker may also examine connections in an OpenSent state if it
- knows the BGP Identifier of the peer by means outside of the
- protocol. If among these connections there is a connection to a
- remote BGP speaker whose BGP Identifier equals the one in the
- OPEN message, then the local system performs the following
- collision resolution procedure: */
-
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- {
- /* Under OpenConfirm status, local peer structure already hold
- remote router ID. */
-
- if (peer != new
- && (peer->status == OpenConfirm || peer->status == OpenSent)
- && sockunion_same (&peer->su, &new->su))
- {
- /* 1. The BGP Identifier of the local system is compared to
- the BGP Identifier of the remote system (as specified in
- the OPEN message). */
-
- if (ntohl (peer->local_id.s_addr) < ntohl (remote_id.s_addr))
- {
- /* 2. If the value of the local BGP Identifier is less
- than the remote one, the local system closes BGP
- connection that already exists (the one that is
- already in the OpenConfirm state), and accepts BGP
- connection initiated by the remote system. */
-
- if (peer->fd >= 0)
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_COLLISION_RESOLUTION);
- return 1;
- }
- else
- {
- /* 3. Otherwise, the local system closes newly created
- BGP connection (the one associated with the newly
- received OPEN message), and continues to use the
- existing one (the one that is already in the
- OpenConfirm state). */
-
- if (new->fd >= 0)
- bgp_notify_send (new, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_COLLISION_RESOLUTION);
- return -1;
- }
- }
- }
- return 0;
-}
-
+bgp_msg_orf_part(struct stream* s, bgp_connection connection,
+ bgp_route_refresh rr) ;
static int
-bgp_open_receive (struct peer *peer, bgp_size_t size)
-{
- int ret;
- u_char version;
- u_char optlen;
- u_int16_t holdtime;
- u_int16_t send_holdtime;
- as_t remote_as;
- as_t as4 = 0;
- struct peer *realpeer;
- struct in_addr remote_id;
- int capability;
- u_int8_t notify_data_remote_as[2];
- u_int8_t notify_data_remote_id[4];
-
- realpeer = NULL;
-
- /* Parse open packet. */
- version = stream_getc (peer->ibuf);
- memcpy (notify_data_remote_as, stream_pnt (peer->ibuf), 2);
- remote_as = stream_getw (peer->ibuf);
- holdtime = stream_getw (peer->ibuf);
- memcpy (notify_data_remote_id, stream_pnt (peer->ibuf), 4);
- remote_id.s_addr = stream_get_ipv4 (peer->ibuf);
-
- /* Receive OPEN message log */
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s rcv OPEN, version %d, remote-as (in open) %u,"
- " holdtime %d, id %s",
- peer->host, version, remote_as, holdtime,
- inet_ntoa (remote_id));
-
- /* BEGIN to read the capability here, but dont do it yet */
- capability = 0;
- optlen = stream_getc (peer->ibuf);
+bgp_msg_orf_unknown(struct stream* s, bgp_orf_unknown_entry orf_unknown,
+ bgp_size_t left) ;
+static int
+bgp_msg_orf_remove_all(struct stream* s, bgp_size_t left) ;
- if (optlen != 0)
- {
- /* We need the as4 capability value *right now* because
- * if it is there, we have not got the remote_as yet, and without
- * that we do not know which peer is connecting to us now.
- */
- as4 = peek_for_as4_capability (peer, optlen);
- }
+static int
+bgp_msg_orf_prefix(struct stream* s, uint8_t common,
+ bgp_orf_prefix_entry orf_prefix, bgp_size_t left) ;
- /* Just in case we have a silly peer who sends AS4 capability set to 0 */
- if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) && !as4)
- {
- zlog_err ("%s bad OPEN, got AS4 capability, but AS4 set to 0",
- peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_BAD_PEER_AS);
- return -1;
- }
+/*------------------------------------------------------------------------------
+ * Make Route-Refresh message(s) and dispatch.
+ *
+ * May return before all required messages have been sent, if the write
+ * buffer is or becomes full. The "next" entry in the "bgp_prefix_orf_update"
+ * allows the process to be continued, later.
+ *
+ * If has to send more than one message, then all but the last will be set
+ * "defer". The last will be set as per the defer flag.
+ *
+ * Supports the status quo, only Address-Prefix ORF.
+ *
+ * Returns: > 0 => all written
+ * 0 => unable to write everything
+ * < 0 => failed -- error event generated
+ */
+extern int
+bgp_msg_send_route_refresh(bgp_connection connection, bgp_route_refresh rr)
+{
+ struct stream *s = connection->obuf ;
+ uint8_t msg_type ;
+ flag_t done ;
+ bgp_size_t msg_len ;
+ int ret ;
- if (remote_as == BGP_AS_TRANS)
- {
- /* Take the AS4 from the capability. We must have received the
- * capability now! Otherwise we have a asn16 peer who uses
- * BGP_AS_TRANS, for some unknown reason.
- */
- if (as4 == BGP_AS_TRANS)
- {
- zlog_err ("%s [AS4] NEW speaker using AS_TRANS for AS4, not allowed",
- peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_BAD_PEER_AS);
- return -1;
- }
-
- if (!as4 && BGP_DEBUG (as4, AS4))
- zlog_debug ("%s [AS4] OPEN remote_as is AS_TRANS, but no AS4."
- " Odd, but proceeding.", peer->host);
- else if (as4 < BGP_AS_MAX && BGP_DEBUG (as4, AS4))
- zlog_debug ("%s [AS4] OPEN remote_as is AS_TRANS, but AS4 (%u) fits "
- "in 2-bytes, very odd peer.", peer->host, as4);
- if (as4)
- remote_as = as4;
- }
- else
- {
- /* We may have a partner with AS4 who has an asno < BGP_AS_MAX */
- /* If we have got the capability, peer->as4cap must match remote_as */
- if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)
- && as4 != remote_as)
- {
- /* raise error, log this, close session */
- zlog_err ("%s bad OPEN, got AS4 capability, but remote_as %u"
- " mismatch with 16bit 'myasn' %u in open",
- peer->host, as4, remote_as);
- bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_BAD_PEER_AS);
- return -1;
- }
- }
+ msg_type = connection->route_refresh_pre ? BGP_MT_ROUTE_REFRESH_pre
+ : BGP_MT_ROUTE_REFRESH ;
+ done = (bgp_orf_get_count(rr) == 0) ;
- /* Lookup peer from Open packet. */
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
+ do
{
- int as = 0;
-
- realpeer = peer_lookup_with_open (&peer->su, remote_as, &remote_id, &as);
-
- if (! realpeer)
- {
- /* Peer's source IP address is check in bgp_accept(), so this
- must be AS number mismatch or remote-id configuration
- mismatch. */
- if (as)
- {
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s bad OPEN, wrong router identifier %s",
- peer->host, inet_ntoa (remote_id));
- bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_BAD_BGP_IDENT,
- notify_data_remote_id, 4);
- }
- else
- {
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s bad OPEN, remote AS is %u, expected %u",
- peer->host, remote_as, peer->as);
- bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_BAD_PEER_AS,
- notify_data_remote_as, 2);
- }
- return -1;
- }
- }
+ if (bgp_connection_write_full(connection))
+ return 0 ;
- /* When collision is detected and this peer is closed. Retrun
- immidiately. */
- ret = bgp_collision_detect (peer, remote_id);
- if (ret < 0)
- return ret;
+ /* Construct BGP message header for new/old form ROUTE-REFRESH */
+ bgp_packet_set_marker(s, msg_type) ;
- /* Hack part. */
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
- {
- if (realpeer->status == Established
- && CHECK_FLAG (realpeer->sflags, PEER_STATUS_NSF_MODE))
- {
- realpeer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION;
- SET_FLAG (realpeer->sflags, PEER_STATUS_NSF_WAIT);
- }
- else if (ret == 0 && realpeer->status != Active
- && realpeer->status != OpenSent
- && realpeer->status != OpenConfirm
- && realpeer->status != Connect)
- {
- /* XXX: This is an awful problem..
- *
- * According to the RFC we should just let this connection (of the
- * accepted 'peer') continue on to Established if the other
- * connection (the 'realpeer' one) is in state Connect, and deal
- * with the more larval FSM as/when it gets far enough to receive
- * an Open. We don't do that though, we instead close the (more
- * developed) accepted connection.
- *
- * This means there's a race, which if hit, can loop:
- *
- * FSM for A FSM for B
- * realpeer accept-peer realpeer accept-peer
- *
- * Connect Connect
- * Active
- * OpenSent OpenSent
- * <arrive here,
- * Notify, delete>
- * Idle Active
- * OpenSent OpenSent
- * <arrive here,
- * Notify, delete>
- * Idle
- * <wait> <wait>
- * Connect Connect
- *
- *
- * If both sides are Quagga, they're almost certain to wait for
- * the same amount of time of course (which doesn't preclude other
- * implementations also waiting for same time). The race is
- * exacerbated by high-latency (in bgpd and/or the network).
- *
- * The reason we do this is because our FSM is tied to our peer
- * structure, which carries our configuration information, etc.
- * I.e. we can't let the accepted-peer FSM continue on as it is,
- * cause it's not associated with any actual peer configuration -
- * it's just a dummy.
- *
- * It's possible we could hack-fix this by just bgp_stop'ing the
- * realpeer and continueing on with the 'transfer FSM' below.
- * Ideally, we need to seperate FSMs from struct peer.
- *
- * Setting one side to passive avoids the race, as a workaround.
- */
- if (BGP_DEBUG (events, EVENTS))
- zlog_debug ("%s peer status is %s close connection",
- realpeer->host, LOOKUP (bgp_status_msg,
- realpeer->status));
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONNECT_REJECT);
-
- return -1;
- }
-
- if (BGP_DEBUG (events, EVENTS))
- zlog_debug ("%s [Event] Transfer accept BGP peer to real (state %s)",
- peer->host,
- LOOKUP (bgp_status_msg, realpeer->status));
-
- bgp_stop (realpeer);
-
- /* Transfer file descriptor. */
- realpeer->fd = peer->fd;
- peer->fd = -1;
-
- /* Transfer input buffer. */
- stream_free (realpeer->ibuf);
- realpeer->ibuf = peer->ibuf;
- realpeer->packet_size = peer->packet_size;
- peer->ibuf = NULL;
-
- /* Transfer status. */
- realpeer->status = peer->status;
- bgp_stop (peer);
-
- /* peer pointer change. Open packet send to neighbor. */
- peer = realpeer;
- bgp_open_send (peer);
- if (peer->fd < 0)
- {
- zlog_err ("bgp_open_receive peer's fd is negative value %d",
- peer->fd);
- return -1;
- }
- BGP_READ_ON (peer->t_read, bgp_read, peer->fd);
- }
+ /* Encode Route Refresh message. */
+ stream_putw(s, rr->afi) ;
+ stream_putc(s, 0);
+ stream_putc(s, rr->safi);
- /* remote router-id check. */
- if (remote_id.s_addr == 0
- || ntohl (remote_id.s_addr) >= 0xe0000000
- || ntohl (peer->local_id.s_addr) == ntohl (remote_id.s_addr))
- {
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s bad OPEN, wrong router identifier %s",
- peer->host, inet_ntoa (remote_id));
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_BAD_BGP_IDENT,
- notify_data_remote_id, 4);
- return -1;
- }
+ /* Process as many (remaining) ORF entries as can into message */
+ if (!done)
+ done = bgp_msg_orf_part(s, connection, rr) ;
- /* Set remote router-id */
- peer->remote_id = remote_id;
+ /* Set BGP message length & dispatch. */
+ msg_len = bgp_packet_set_size(s) ;
- /* Peer BGP version check. */
- if (version != BGP_VERSION_4)
- {
- u_int8_t maxver = BGP_VERSION_4;
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s bad protocol version, remote requested %d, local request %d",
- peer->host, version, BGP_VERSION_4);
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_UNSUP_VERSION,
- &maxver, 1);
- return -1;
- }
-
- /* Check neighbor as number. */
- if (remote_as != peer->as)
- {
if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s bad OPEN, remote AS is %u, expected %u",
- peer->host, remote_as, peer->as);
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_BAD_PEER_AS,
- notify_data_remote_as, 2);
- return -1;
- }
-
- /* From the rfc: Upon receipt of an OPEN message, a BGP speaker MUST
- calculate the value of the Hold Timer by using the smaller of its
- configured Hold Time and the Hold Time received in the OPEN message.
- The Hold Time MUST be either zero or at least three seconds. An
- implementation may reject connections on the basis of the Hold Time. */
-
- if (holdtime < 3 && holdtime != 0)
- {
- bgp_notify_send (peer,
- BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_UNACEP_HOLDTIME);
- return -1;
- }
-
- /* From the rfc: A reasonable maximum time between KEEPALIVE messages
- would be one third of the Hold Time interval. KEEPALIVE messages
- MUST NOT be sent more frequently than one per second. An
- implementation MAY adjust the rate at which it sends KEEPALIVE
- messages as a function of the Hold Time interval. */
-
- if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER))
- send_holdtime = peer->holdtime;
- else
- send_holdtime = peer->bgp->default_holdtime;
+ zlog_debug ("%s sending REFRESH_REQ for afi/safi: %d/%d length %d",
+ connection->host, rr->afi, rr->safi, msg_len) ;
- if (holdtime < send_holdtime)
- peer->v_holdtime = holdtime;
- else
- peer->v_holdtime = send_holdtime;
-
- peer->v_keepalive = peer->v_holdtime / 3;
-
- /* Open option part parse. */
- if (optlen != 0)
- {
- ret = bgp_open_option_parse (peer, optlen, &capability);
+ ret = bgp_connection_write(connection, s) ;
if (ret < 0)
- return ret;
- }
- else
- {
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s rcvd OPEN w/ OPTION parameter len: 0",
- peer->host);
- }
+ return ret ;
- /* Override capability. */
- if (! capability || CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
- {
- peer->afc_nego[AFI_IP][SAFI_UNICAST] = peer->afc[AFI_IP][SAFI_UNICAST];
- peer->afc_nego[AFI_IP][SAFI_MULTICAST] = peer->afc[AFI_IP][SAFI_MULTICAST];
- peer->afc_nego[AFI_IP6][SAFI_UNICAST] = peer->afc[AFI_IP6][SAFI_UNICAST];
- peer->afc_nego[AFI_IP6][SAFI_MULTICAST] = peer->afc[AFI_IP6][SAFI_MULTICAST];
- }
+ } while (!done) ;
- /* Get sockname. */
- bgp_getsockname (peer);
+ return done ;
+} ;
- BGP_EVENT_ADD (peer, Receive_OPEN_message);
+/*------------------------------------------------------------------------------
+ * Set the current ORF entry length (if any)
+ *
+ * Returns total length of BGP message.
+ */
+inline static bgp_size_t
+bgp_msg_set_orf_length(struct stream* s, unsigned long elenp)
+{
+ bgp_size_t length = stream_get_endp(s) ;
- peer->packet_size = 0;
- if (peer->ibuf)
- stream_reset (peer->ibuf);
+ if (elenp != 0)
+ stream_putw_at(s, elenp, length - elenp - 2) ;
- return 0;
-}
+ return length ;
+} ;
-/* Parse BGP Update packet and make attribute object. */
+/*------------------------------------------------------------------------------
+ * Put ORF entries to the given stream until run out of entries or run out
+ * of room in the message.
+ *
+ * There MUST BE at least one ORF entry to go.
+ *
+ * Returns true <=> done all available entries.
+ */
static int
-bgp_update_receive (struct peer *peer, bgp_size_t size)
+bgp_msg_orf_part(struct stream* s, bgp_connection connection,
+ bgp_route_refresh rr)
{
- int ret;
- u_char *end;
- struct stream *s;
- struct attr attr;
- bgp_size_t attribute_len;
- bgp_size_t update_len;
- bgp_size_t withdraw_len;
- struct bgp_nlri update;
- struct bgp_nlri withdraw;
- struct bgp_nlri mp_update;
- struct bgp_nlri mp_withdraw;
- char attrstr[BUFSIZ] = "";
-
- /* Status must be Established. */
- if (peer->status != Established)
- {
- zlog_err ("%s [FSM] Update packet received under status %s",
- peer->host, LOOKUP (bgp_status_msg, peer->status));
- bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0);
- return -1;
- }
-
- /* Set initial values. */
- memset (&attr, 0, sizeof (struct attr));
- memset (&update, 0, sizeof (struct bgp_nlri));
- memset (&withdraw, 0, sizeof (struct bgp_nlri));
- memset (&mp_update, 0, sizeof (struct bgp_nlri));
- memset (&mp_withdraw, 0, sizeof (struct bgp_nlri));
-
- s = peer->ibuf;
- end = stream_pnt (s) + size;
-
- /* RFC1771 6.3 If the Unfeasible Routes Length or Total Attribute
- Length is too large (i.e., if Unfeasible Routes Length + Total
- Attribute Length + 23 exceeds the message Length), then the Error
- Subcode is set to Malformed Attribute List. */
- if (stream_pnt (s) + 2 > end)
- {
- zlog_err ("%s [Error] Update packet error"
- " (packet length is short for unfeasible length)",
- peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_ATTR);
- return -1;
- }
-
- /* Unfeasible Route Length. */
- withdraw_len = stream_getw (s);
+ bgp_orf_entry entry ;
- /* Unfeasible Route Length check. */
- if (stream_pnt (s) + withdraw_len > end)
- {
- zlog_err ("%s [Error] Update packet error"
- " (packet unfeasible length overflow %d)",
- peer->host, withdraw_len);
- bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_ATTR);
- return -1;
- }
+ uint8_t orf_type ;
+ uint8_t orf_type_sent ;
- /* Unfeasible Route packet format check. */
- if (withdraw_len > 0)
- {
- ret = bgp_nlri_sanity_check (peer, AFI_IP, stream_pnt (s), withdraw_len);
- if (ret < 0)
- return -1;
+ unsigned long whenp ; /* where the "when" byte is */
+ unsigned long elenp ; /* where the entries length is */
- if (BGP_DEBUG (packet, PACKET_RECV))
- zlog_debug ("%s [Update:RECV] Unfeasible NLRI received", peer->host);
+ bgp_size_t left ;
+ bgp_size_t length ;
+ flag_t done ;
+ flag_t first ;
- withdraw.afi = AFI_IP;
- withdraw.safi = SAFI_UNICAST;
- withdraw.nlri = stream_pnt (s);
- withdraw.length = withdraw_len;
- stream_forward_getp (s, withdraw_len);
- }
-
- /* Attribute total length check. */
- if (stream_pnt (s) + 2 > end)
- {
- zlog_warn ("%s [Error] Packet Error"
- " (update packet is short for attribute length)",
- peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_ATTR);
- return -1;
- }
+ /* Heading for Prefix-Address ORF type section */
+ whenp = stream_get_endp(s) ; /* position of "when" */
+ stream_putc(s, rr->defer ? BGP_ORF_WTR_DEFER : BGP_ORF_WTR_IMMEDIATE) ;
- /* Fetch attribute total length. */
- attribute_len = stream_getw (s);
+ /* Process ORF entries until run out of entries or space */
- /* Attribute length check. */
- if (stream_pnt (s) + attribute_len > end)
- {
- zlog_warn ("%s [Error] Packet Error"
- " (update packet attribute length overflow %d)",
- peer->host, attribute_len);
- bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_ATTR);
- return -1;
- }
+ elenp = 0 ; /* no entries length, yet */
+ orf_type = 0 ; /* no ORF type, yet */
- /* Parse attribute when it exists. */
- if (attribute_len)
- {
- ret = bgp_attr_parse (peer, &attr, attribute_len,
- &mp_update, &mp_withdraw);
- if (ret < 0)
- return -1;
- }
+ first = 1 ; /* next entry is first of its ORF type */
- /* Logging the attribute. */
- if (BGP_DEBUG (update, UPDATE_IN))
+ while (1)
{
- ret= bgp_dump_attr (peer, &attr, attrstr, BUFSIZ);
+ entry = bgp_orf_get_entry(rr, rr->next) ;
+ done = (entry == NULL) ;
- if (ret)
- zlog (peer->log, LOG_DEBUG, "%s rcvd UPDATE w/ attr: %s",
- peer->host, attrstr);
- }
+ if (done)
+ break ;
- /* Network Layer Reachability Information. */
- update_len = end - stream_pnt (s);
+ /* How much space is there left -- give up if very little
+ *
+ * What is "very little" is arbitrary, BUT MUST cover the ORF Type
+ * byte and the Length of ORF entries word, AT LEAST.
+ * */
+ left = BGP_MSG_MAX_L - stream_get_endp(s) ;
- if (update_len)
- {
- /* Check NLRI packet format and prefix length. */
- ret = bgp_nlri_sanity_check (peer, AFI_IP, stream_pnt (s), update_len);
- if (ret < 0)
- return -1;
-
- /* Set NLRI portion to structure. */
- update.afi = AFI_IP;
- update.safi = SAFI_UNICAST;
- update.nlri = stream_pnt (s);
- update.length = update_len;
- stream_forward_getp (s, update_len);
- }
+ if (left < 16)
+ break ; /* NB: done == false */
- /* NLRI is processed only when the peer is configured specific
- Address Family and Subsequent Address Family. */
- if (peer->afc[AFI_IP][SAFI_UNICAST])
- {
- if (withdraw.length)
- bgp_nlri_parse (peer, NULL, &withdraw);
-
- if (update.length)
- {
- /* We check well-known attribute only for IPv4 unicast
- update. */
- ret = bgp_attr_check (peer, &attr);
- if (ret < 0)
- return -1;
-
- bgp_nlri_parse (peer, &attr, &update);
- }
-
- if (mp_update.length
- && mp_update.afi == AFI_IP
- && mp_update.safi == SAFI_UNICAST)
- bgp_nlri_parse (peer, &attr, &mp_update);
-
- if (mp_withdraw.length
- && mp_withdraw.afi == AFI_IP
- && mp_withdraw.safi == SAFI_UNICAST)
- bgp_nlri_parse (peer, NULL, &mp_withdraw);
-
- if (! attribute_len && ! withdraw_len)
- {
- /* End-of-RIB received */
- SET_FLAG (peer->af_sflags[AFI_IP][SAFI_UNICAST],
- PEER_STATUS_EOR_RECEIVED);
-
- /* NSF delete stale route */
- if (peer->nsf[AFI_IP][SAFI_UNICAST])
- bgp_clear_stale_route (peer, AFI_IP, SAFI_UNICAST);
-
- if (BGP_DEBUG (normal, NORMAL))
- zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for IPv4 Unicast from %s",
- peer->host);
- }
- }
- if (peer->afc[AFI_IP][SAFI_MULTICAST])
- {
- if (mp_update.length
- && mp_update.afi == AFI_IP
- && mp_update.safi == SAFI_MULTICAST)
- bgp_nlri_parse (peer, &attr, &mp_update);
-
- if (mp_withdraw.length
- && mp_withdraw.afi == AFI_IP
- && mp_withdraw.safi == SAFI_MULTICAST)
- bgp_nlri_parse (peer, NULL, &mp_withdraw);
-
- if (! withdraw_len
- && mp_withdraw.afi == AFI_IP
- && mp_withdraw.safi == SAFI_MULTICAST
- && mp_withdraw.length == 0)
- {
- /* End-of-RIB received */
- SET_FLAG (peer->af_sflags[AFI_IP][SAFI_MULTICAST],
- PEER_STATUS_EOR_RECEIVED);
-
- /* NSF delete stale route */
- if (peer->nsf[AFI_IP][SAFI_MULTICAST])
- bgp_clear_stale_route (peer, AFI_IP, SAFI_MULTICAST);
-
- if (BGP_DEBUG (normal, NORMAL))
- zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for IPv4 Multicast from %s",
- peer->host);
- }
- }
- if (peer->afc[AFI_IP6][SAFI_UNICAST])
- {
- if (mp_update.length
- && mp_update.afi == AFI_IP6
- && mp_update.safi == SAFI_UNICAST)
- bgp_nlri_parse (peer, &attr, &mp_update);
-
- if (mp_withdraw.length
- && mp_withdraw.afi == AFI_IP6
- && mp_withdraw.safi == SAFI_UNICAST)
- bgp_nlri_parse (peer, NULL, &mp_withdraw);
-
- if (! withdraw_len
- && mp_withdraw.afi == AFI_IP6
- && mp_withdraw.safi == SAFI_UNICAST
- && mp_withdraw.length == 0)
- {
- /* End-of-RIB received */
- SET_FLAG (peer->af_sflags[AFI_IP6][SAFI_UNICAST], PEER_STATUS_EOR_RECEIVED);
-
- /* NSF delete stale route */
- if (peer->nsf[AFI_IP6][SAFI_UNICAST])
- bgp_clear_stale_route (peer, AFI_IP6, SAFI_UNICAST);
-
- if (BGP_DEBUG (normal, NORMAL))
- zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for IPv6 Unicast from %s",
- peer->host);
- }
- }
- if (peer->afc[AFI_IP6][SAFI_MULTICAST])
- {
- if (mp_update.length
- && mp_update.afi == AFI_IP6
- && mp_update.safi == SAFI_MULTICAST)
- bgp_nlri_parse (peer, &attr, &mp_update);
-
- if (mp_withdraw.length
- && mp_withdraw.afi == AFI_IP6
- && mp_withdraw.safi == SAFI_MULTICAST)
- bgp_nlri_parse (peer, NULL, &mp_withdraw);
-
- if (! withdraw_len
- && mp_withdraw.afi == AFI_IP6
- && mp_withdraw.safi == SAFI_MULTICAST
- && mp_withdraw.length == 0)
- {
- /* End-of-RIB received */
-
- /* NSF delete stale route */
- if (peer->nsf[AFI_IP6][SAFI_MULTICAST])
- bgp_clear_stale_route (peer, AFI_IP6, SAFI_MULTICAST);
-
- if (BGP_DEBUG (update, UPDATE_IN))
- zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for IPv6 Multicast from %s",
- peer->host);
- }
- }
- if (peer->afc[AFI_IP][SAFI_MPLS_VPN])
- {
- if (mp_update.length
- && mp_update.afi == AFI_IP
- && mp_update.safi == BGP_SAFI_VPNV4)
- bgp_nlri_parse_vpnv4 (peer, &attr, &mp_update);
-
- if (mp_withdraw.length
- && mp_withdraw.afi == AFI_IP
- && mp_withdraw.safi == BGP_SAFI_VPNV4)
- bgp_nlri_parse_vpnv4 (peer, NULL, &mp_withdraw);
-
- if (! withdraw_len
- && mp_withdraw.afi == AFI_IP
- && mp_withdraw.safi == BGP_SAFI_VPNV4
- && mp_withdraw.length == 0)
- {
- /* End-of-RIB received */
-
- if (BGP_DEBUG (update, UPDATE_IN))
- zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for VPNv4 Unicast from %s",
- peer->host);
- }
- }
-
- /* Everything is done. We unintern temporary structures which
- interned in bgp_attr_parse(). */
- if (attr.aspath)
- aspath_unintern (attr.aspath);
- if (attr.community)
- community_unintern (attr.community);
- if (attr.extra)
- {
- if (attr.extra->ecommunity)
- ecommunity_unintern (attr.extra->ecommunity);
- if (attr.extra->cluster)
- cluster_unintern (attr.extra->cluster);
- if (attr.extra->transit)
- transit_unintern (attr.extra->transit);
- bgp_attr_extra_free (&attr);
- }
+ confirm(16 > BGP_ORF_MIN_L) ; /* Type & Length */
- /* If peering is stopped due to some reason, do not generate BGP
- event. */
- if (peer->status != Established)
- return 0;
+ /* Start new collection of ORF entries, if required. */
+ if (first || (orf_type != entry->orf_type))
+ {
+ /* fill in length of previous ORF entries, if any */
+ bgp_msg_set_orf_length(s, elenp) ;
- /* Increment packet counter. */
- peer->update_in++;
- peer->update_time = time (NULL);
+ /* set type and dummy entries length. */
+ orf_type = entry->orf_type ;
+ orf_type_sent = entry->orf_type ;
- /* Generate BGP event. */
- BGP_EVENT_ADD (peer, Receive_UPDATE_message);
+ if ((orf_type == BGP_ORF_T_PREFIX) && connection->route_refresh_pre)
+ orf_type_sent = BGP_ORF_T_PREFIX_pre ;
- return 0;
-}
-
-/* Notify message treatment function. */
-static void
-bgp_notify_receive (struct peer *peer, bgp_size_t size)
-{
- struct bgp_notify bgp_notify;
+ stream_putc(s, orf_type_sent) ; /* ORF entries type */
- if (peer->notify.data)
- {
- XFREE (MTYPE_TMP, peer->notify.data);
- peer->notify.data = NULL;
- peer->notify.length = 0;
- }
+ elenp = stream_get_endp(s) ; /* offset of the length */
+ stream_putw(s, 0) ; /* length of ORF entries */
- bgp_notify.code = stream_getc (peer->ibuf);
- bgp_notify.subcode = stream_getc (peer->ibuf);
- bgp_notify.length = size - 2;
- bgp_notify.data = NULL;
+ first = 1 ; /* next ORF entry is first of collection */
+ } ;
- /* Preserv notify code and sub code. */
- peer->notify.code = bgp_notify.code;
- peer->notify.subcode = bgp_notify.subcode;
- /* For further diagnostic record returned Data. */
- if (bgp_notify.length)
- {
- peer->notify.length = size - 2;
- peer->notify.data = XMALLOC (MTYPE_TMP, size - 2);
- memcpy (peer->notify.data, stream_pnt (peer->ibuf), size - 2);
- }
+ /* Insert the entry, if will fit.
+ *
+ * sets done <=> fitted
+ */
+ if (entry->unknown)
+ done = bgp_msg_orf_unknown(s, &entry->body.orf_unknown, left) ;
+ else
+ {
+ if (entry->remove_all)
+ done = bgp_msg_orf_remove_all(s, left) ;
+ else
+ {
+ uint8_t common = (entry->remove ? BGP_ORF_EA_REMOVE
+ : BGP_ORF_EA_ADD)
+ | (entry->deny ? BGP_ORF_EA_DENY
+ : BGP_ORF_EA_PERMIT) ;
+ switch (entry->orf_type)
+ {
+ case BGP_ORF_T_PREFIX:
+ done = bgp_msg_orf_prefix(s, common,
+ &entry->body.orf_prefix, left) ;
+ break ;
+ default:
+ zabort("unknown ORF type") ;
+ break ;
+ } ;
+ } ;
+ } ;
+
+ /* exit loop now if not enough room for current ORF entry */
+ if (!done)
+ break ;
+
+ /* Done ORF entry. Step to the next. NB: done == true */
+ ++rr->next ;
+ first = 0 ; /* no longer first */
+ } ;
+
+ /* If not done, need to:
+ *
+ * a) force defer,
+ * b) undo ORF entries if none output of current type
+ *
+ */
+ if (!done)
+ {
+ stream_putc_at(s, whenp , BGP_ORF_WTR_DEFER) ;
+
+ if (first)
+ {
+ stream_set_endp(s, elenp - 1) ;
+ elenp = 0 ; /* no entries length to set */
+ } ;
+ } ;
+
+ /* fill in length of last ORF entries (if any) */
+ length = bgp_msg_set_orf_length(s, elenp) ;
+
+ /* Something has gone wrong if nothing has been output after the "when"
+ * byte. Two possibilities:
+ *
+ * a) have been called again after having reported "done" (so there are
+ * no more entries to deal with.
+ *
+ * b) have been asked to output an "unknown" ORF entry which is too long
+ * for a BGP message !!
+ */
+ if (length == (whenp + 1))
+ {
+ if (entry == NULL)
+ zabort("called bgp_msg_send_route_refresh() after said was done") ;
+
+ if (entry->unknown)
+ zlog_err("%s sending REFRESH_REQ with impossible length (%d) ORF",
+ connection->host, entry->body.orf_unknown.length) ;
+ else
+ zabort("failed to put even one ORF entry") ;
- /* For debug */
- {
- int i;
- int first = 0;
- char c[4];
+ done = 1 ; /* force done */
+ } ;
- if (bgp_notify.length)
- {
- bgp_notify.data = XMALLOC (MTYPE_TMP, bgp_notify.length * 3);
- for (i = 0; i < bgp_notify.length; i++)
- if (first)
- {
- sprintf (c, " %02x", stream_getc (peer->ibuf));
- strcat (bgp_notify.data, c);
- }
- else
- {
- first = 1;
- sprintf (c, "%02x", stream_getc (peer->ibuf));
- strcpy (bgp_notify.data, c);
- }
- }
-
- bgp_notify_print(peer, &bgp_notify, "received");
- if (bgp_notify.data)
- XFREE (MTYPE_TMP, bgp_notify.data);
- }
-
- /* peer count update */
- peer->notify_in++;
-
- if (peer->status == Established)
- peer->last_reset = PEER_DOWN_NOTIFY_RECEIVED;
-
- /* We have to check for Notify with Unsupported Optional Parameter.
- in that case we fallback to open without the capability option.
- But this done in bgp_stop. We just mark it here to avoid changing
- the fsm tables. */
- if (bgp_notify.code == BGP_NOTIFY_OPEN_ERR &&
- 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);
-}
+ return done ;
+} ;
-/* Keepalive treatment function -- get keepalive send keepalive */
-static void
-bgp_keepalive_receive (struct peer *peer, bgp_size_t size)
+/*------------------------------------------------------------------------------
+ * Put given unknown ORF entry to stream -- verbatim -- if possible.
+ */
+static int
+bgp_msg_orf_unknown(struct stream* s, bgp_orf_unknown_entry orf_unknown,
+ bgp_size_t left)
{
- if (BGP_DEBUG (keepalive, KEEPALIVE))
- zlog_debug ("%s KEEPALIVE rcvd", peer->host);
+ if (left < orf_unknown->length)
+ return 0 ;
- BGP_EVENT_ADD (peer, Receive_KEEPALIVE_message);
-}
+ stream_write(s, orf_unknown->data, orf_unknown->length) ;
+ return 1 ;
+} ;
-/* Route refresh message is received. */
-static void
-bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
+/*------------------------------------------------------------------------------
+ * Put remove all ORF entry to stream -- if possible.
+ */
+static int
+bgp_msg_orf_remove_all(struct stream* s, bgp_size_t left)
{
- afi_t afi;
- safi_t safi;
- u_char reserved;
- struct stream *s;
+ if (left == 1) /* only one byte required ! */
+ return 0 ;
- /* If peer does not have the capability, send notification. */
- if (! CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_ADV))
- {
- plog_err (peer->log, "%s [Error] BGP route refresh is not enabled",
- peer->host);
- bgp_notify_send (peer,
- BGP_NOTIFY_HEADER_ERR,
- BGP_NOTIFY_HEADER_BAD_MESTYPE);
- return;
- }
-
- /* Status must be Established. */
- if (peer->status != Established)
- {
- plog_err (peer->log,
- "%s [Error] Route refresh packet received under status %s",
- peer->host, LOOKUP (bgp_status_msg, peer->status));
- bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0);
- return;
- }
-
- s = peer->ibuf;
-
- /* Parse packet. */
- afi = stream_getw (s);
- reserved = stream_getc (s);
- safi = stream_getc (s);
-
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s rcvd REFRESH_REQ for afi/safi: %d/%d",
- peer->host, afi, safi);
-
- /* Check AFI and SAFI. */
- if ((afi != AFI_IP && afi != AFI_IP6)
- || (safi != SAFI_UNICAST && safi != SAFI_MULTICAST
- && safi != BGP_SAFI_VPNV4))
- {
- if (BGP_DEBUG (normal, NORMAL))
- {
- zlog_debug ("%s REFRESH_REQ for unrecognized afi/safi: %d/%d - ignored",
- peer->host, afi, safi);
- }
- return;
- }
-
- /* Adjust safi code. */
- if (safi == BGP_SAFI_VPNV4)
- safi = SAFI_MPLS_VPN;
-
- if (size != BGP_MSG_ROUTE_REFRESH_MIN_SIZE - BGP_HEADER_SIZE)
- {
- u_char *end;
- u_char when_to_refresh;
- u_char orf_type;
- u_int16_t orf_len;
-
- if (size - (BGP_MSG_ROUTE_REFRESH_MIN_SIZE - BGP_HEADER_SIZE) < 5)
- {
- zlog_info ("%s ORF route refresh length error", peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
- return;
- }
-
- when_to_refresh = stream_getc (s);
- end = stream_pnt (s) + (size - 5);
-
- while ((stream_pnt (s) + 2) < end)
- {
- orf_type = stream_getc (s);
- orf_len = stream_getw (s);
-
- /* orf_len in bounds? */
- if ((stream_pnt (s) + orf_len) > end)
- break; /* XXX: Notify instead?? */
- if (orf_type == ORF_TYPE_PREFIX
- || orf_type == ORF_TYPE_PREFIX_OLD)
- {
- u_char *p_pnt = stream_pnt (s);
- u_char *p_end = stream_pnt (s) + orf_len;
- struct orf_prefix orfp;
- u_char common = 0;
- u_int32_t seq;
- int psize;
- char name[BUFSIZ];
- char buf[BUFSIZ];
- int ret;
-
- if (BGP_DEBUG (normal, NORMAL))
- {
- zlog_debug ("%s rcvd Prefixlist ORF(%d) length %d",
- peer->host, orf_type, orf_len);
- }
-
- /* we're going to read at least 1 byte of common ORF header,
- * and 7 bytes of ORF Address-filter entry from the stream
- */
- if (orf_len < 7)
- break;
-
- /* ORF prefix-list name */
- sprintf (name, "%s.%d.%d", peer->host, afi, safi);
-
- while (p_pnt < p_end)
- {
- memset (&orfp, 0, sizeof (struct orf_prefix));
- common = *p_pnt++;
- if (common & ORF_COMMON_PART_REMOVE_ALL)
- {
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s rcvd Remove-All pfxlist ORF request", peer->host);
- 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);
- p_pnt += psize;
-
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s rcvd %s %s seq %u %s/%d ge %d le %d",
- 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)
- {
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s Received misformatted prefixlist ORF. Remove All pfxlist", peer->host);
- prefix_bgp_orf_remove_all (name);
- break;
- }
- }
- peer->orf_plist[afi][safi] =
- prefix_list_lookup (AFI_ORF_PREFIX, name);
- }
- stream_forward_getp (s, orf_len);
- }
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s rcvd Refresh %s ORF request", peer->host,
- when_to_refresh == REFRESH_DEFER ? "Defer" : "Immediate");
- if (when_to_refresh == REFRESH_DEFER)
- return;
- }
-
- /* First update is deferred until ORF or ROUTE-REFRESH is received */
- if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH))
- UNSET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH);
-
- /* Perform route refreshment to the peer */
- bgp_announce_route (peer, afi, safi);
-}
+ stream_putc(s, BGP_ORF_EA_RM_ALL) ;
+ return 1 ;
+} ;
+/*------------------------------------------------------------------------------
+ * Put given Address-Prefix ORF entry to stream -- if possible.
+ */
static int
-bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length)
+bgp_msg_orf_prefix(struct stream* s, uint8_t common,
+ bgp_orf_prefix_entry orf_prefix, bgp_size_t left)
{
- u_char *end;
- struct capability_mp_data mpc;
- struct capability_header *hdr;
- u_char action;
- struct bgp *bgp;
- afi_t afi;
- safi_t safi;
-
- bgp = peer->bgp;
- end = pnt + length;
-
- while (pnt < end)
- {
- /* We need at least action, capability code and capability length. */
- if (pnt + 3 > end)
- {
- zlog_info ("%s Capability length error", peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
- return -1;
- }
- action = *pnt;
- hdr = (struct capability_header *)(pnt + 1);
-
- /* Action value check. */
- if (action != CAPABILITY_ACTION_SET
- && action != CAPABILITY_ACTION_UNSET)
- {
- zlog_info ("%s Capability Action Value error %d",
- peer->host, action);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
- return -1;
- }
-
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s CAPABILITY has action: %d, code: %u, length %u",
- peer->host, action, hdr->code, hdr->length);
-
- /* Capability length check. */
- if ((pnt + hdr->length + 3) > end)
- {
- zlog_info ("%s Capability length error", peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
- return -1;
- }
+ bgp_size_t plen = (orf_prefix->pfx.prefixlen + 7) / 8 ;
- /* Fetch structure to the byte stream. */
- memcpy (&mpc, pnt + 3, sizeof (struct capability_mp_data));
+ if (left < (BGP_ORF_E_P_MIN_L + plen))
+ return 0 ;
- /* We know MP Capability Code. */
- if (hdr->code == CAPABILITY_CODE_MP)
- {
- afi = ntohs (mpc.afi);
- safi = mpc.safi;
+ stream_putc(s, common) ;
+ stream_putl(s, orf_prefix->seq) ;
+ stream_putc(s, orf_prefix->min) ;
+ stream_putc(s, orf_prefix->max) ;
+ stream_putc(s, orf_prefix->pfx.prefixlen) ;
+ stream_write(s, &orf_prefix->pfx.u.prefix, plen) ;
- /* Ignore capability when override-capability is set. */
- if (CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
- continue;
+ return 1 ;
+} ;
- if (!bgp_afi_safi_valid_indices (afi, &safi))
- {
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s Dynamic Capability MP_EXT afi/safi invalid "
- "(%u/%u)", peer->host, afi, safi);
- continue;
- }
-
- /* Address family check. */
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s CAPABILITY has %s MP_EXT CAP for afi/safi: %u/%u",
- peer->host,
- action == CAPABILITY_ACTION_SET
- ? "Advertising" : "Removing",
- ntohs(mpc.afi) , mpc.safi);
-
- if (action == CAPABILITY_ACTION_SET)
- {
- peer->afc_recv[afi][safi] = 1;
- if (peer->afc[afi][safi])
- {
- peer->afc_nego[afi][safi] = 1;
- bgp_announce_route (peer, afi, safi);
- }
- }
- else
- {
- peer->afc_recv[afi][safi] = 0;
- peer->afc_nego[afi][safi] = 0;
-
- if (peer_active_nego (peer))
- bgp_clear_route (peer, afi, safi, BGP_CLEAR_ROUTE_NORMAL);
- else
- BGP_EVENT_ADD (peer, BGP_Stop);
- }
- }
- else
- {
- zlog_warn ("%s unrecognized capability code: %d - ignored",
- peer->host, hdr->code);
- }
- pnt += hdr->length + 3;
- }
- return 0;
-}
+/*==============================================================================
+ * End-of-RIB -- send an End-of-RIB BGP message (see Graceful Restart)
+ */
-/* Dynamic Capability is received.
+/*------------------------------------------------------------------------------
+ * Make End-of-RIB message and dispatch.
*
- * This is exported for unit-test purposes
- */ extern int bgp_capability_receive(struct peer*, bgp_size_t) ;
-int
-bgp_capability_receive (struct peer *peer, bgp_size_t size)
+ *
+ *
+ * Returns: 2 => written to TCP -- it's gone
+ * 1 => written to wbuff -- waiting for socket
+ * 0 => nothing written -- wbuff was not empty !
+ * -1 => failed -- error event generated
+ */
+extern int
+bgp_msg_send_end_of_rib(bgp_connection connection, iAFI_t afi, iSAFI_t safi)
{
- u_char *pnt;
+ struct stream *s = connection->obuf ;
- /* Fetch pointer. */
- pnt = stream_pnt (peer->ibuf);
+ if (!bgp_connection_write_empty(connection))
+ return 0 ;
- if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s rcv CAPABILITY", peer->host);
+ /* Make UPDATE message header */
+ bgp_packet_set_marker(s, BGP_MSG_UPDATE) ;
- /* If peer does not have the capability, send notification. */
- if (! CHECK_FLAG (peer->cap, PEER_CAP_DYNAMIC_ADV))
- {
- plog_err (peer->log, "%s [Error] BGP dynamic capability is not enabled",
- peer->host);
- bgp_notify_send (peer,
- BGP_NOTIFY_HEADER_ERR,
- BGP_NOTIFY_HEADER_BAD_MESTYPE);
- return -1;
- }
+ /* Minimum size UPDATE */
+ stream_putw(s, 0) ; /* no Withdrawn Routes */
+ stream_putw(s, 0) ; /* no Attributes => no NLRI */
- /* Status must be Established. */
- if (peer->status != Established)
- {
- plog_err (peer->log,
- "%s [Error] Dynamic capability packet received under status %s", peer->host, LOOKUP (bgp_status_msg, peer->status));
- bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0);
- return -1;
- }
+ /* If not IPv4/Unicast, need empty MP Unreachable attribute */
+ if ((afi != iAFI_IP) || (safi != iSAFI_Unicast))
+ {
+ bgp_size_t attrp = stream_get_endp(s) ;
- /* Parse packet. */
- return bgp_capability_msg_parse (peer, pnt, size);
-}
+ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
+ stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
+ stream_putc (s, 3);
+ stream_putw (s, afi);
+ stream_putc (s, safi);
-/* BGP read utility function. */
-static int
-bgp_read_packet (struct peer *peer)
-{
- int nbytes;
- int readsize;
-
- readsize = peer->packet_size - stream_get_endp (peer->ibuf);
-
- /* If size is zero then return. */
- if (! readsize)
- return 0;
-
- /* Read packet from fd. */
- nbytes = stream_read_unblock (peer->ibuf, peer->fd, readsize);
-
- /* If read byte is smaller than zero then error occured. */
- if (nbytes < 0)
- {
- if (errno == EAGAIN)
- return -1;
-
- plog_err (peer->log, "%s [Error] bgp_read_packet error: %s",
- peer->host, safe_strerror (errno));
-
- if (peer->status == Established)
- {
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_MODE))
- {
- peer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION;
- SET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT);
- }
- else
- peer->last_reset = PEER_DOWN_CLOSE_SESSION;
- }
-
- BGP_EVENT_ADD (peer, TCP_fatal_error);
- return -1;
+ stream_putw_at(s, attrp-2, stream_get_endp(s) - attrp) ;
}
- /* When read byte is zero : clear bgp peer and return */
- if (nbytes == 0)
- {
- if (BGP_DEBUG (events, EVENTS))
- plog_debug (peer->log, "%s [Event] BGP connection closed fd %d",
- peer->host, peer->fd);
-
- if (peer->status == Established)
- {
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_MODE))
- {
- peer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION;
- SET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT);
- }
- else
- peer->last_reset = PEER_DOWN_CLOSE_SESSION;
- }
-
- BGP_EVENT_ADD (peer, TCP_connection_closed);
- return -1;
- }
+ bgp_packet_set_size(s);
- /* We read partial packet. */
- if (stream_get_endp (peer->ibuf) != peer->packet_size)
- return -1;
+ if (BGP_DEBUG (normal, NORMAL))
+ zlog_debug ("send End-of-RIB for %s to %s", afi_safi_print (afi, safi),
+ connection->host) ;
- return 0;
-}
+ /* Finally -- write the obuf away */
+ return bgp_connection_write(connection, s) ;
+} ;
-/* Marker check. */
-static int
-bgp_marker_all_one (struct stream *s, int length)
+/*==============================================================================
+ * Utilities for creating BGP messages
+ */
+ /* 0 1 2 3 4 5 6 7 */
+static const char bgp_header[] = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" /* 8 */
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" /* 16 */
+ "\x00" ;
+CONFIRM(sizeof(bgp_header) == (BGP_MARKER_SIZE + 2)) ;
+
+/*------------------------------------------------------------------------------
+ * Insert BGP message standard header
+ *
+ * 16 bytes of 0xFF
+ * 2 bytes -- total length of message -- filled in later
+ * 1 byte -- the type of message as given
+ */
+extern int
+bgp_packet_set_marker(struct stream *s, uint8_t type)
{
- int i;
+ /* Fill in marker & dummy total length (to be filled in later on) */
+ stream_write(s, bgp_header, BGP_MARKER_SIZE + 2) ;
- for (i = 0; i < length; i++)
- if (s->data[i] != 0xff)
- return 0;
+ /* BGP packet type. */
+ stream_putc (s, type);
- return 1;
-}
+ /* Return current stream size. */
+ return stream_get_endp (s);
+} ;
-/* Starting point of packet process function. */
-int
-bgp_read (struct thread *thread)
+/*------------------------------------------------------------------------------
+ * Set BGP packet header size entry and return same.
+ */
+extern int
+bgp_packet_set_size (struct stream *s)
{
- int ret;
- u_char type = 0;
- struct peer *peer;
- bgp_size_t size;
- char notify_data_length[2];
-
- /* Yes first of all get peer pointer. */
- peer = THREAD_ARG (thread);
- peer->t_read = NULL;
-
- /* For non-blocking IO check. */
- if (peer->status == Connect)
- {
- bgp_connect_check (peer);
- goto done;
- }
- else
- {
- if (peer->fd < 0)
- {
- zlog_err ("bgp_read peer's fd is negative value %d", peer->fd);
- return -1;
- }
- BGP_READ_ON (peer->t_read, bgp_read, peer->fd);
- }
-
- /* Read packet header to determine type of the packet */
- if (peer->packet_size == 0)
- peer->packet_size = BGP_HEADER_SIZE;
-
- if (stream_get_endp (peer->ibuf) < BGP_HEADER_SIZE)
- {
- ret = bgp_read_packet (peer);
-
- /* Header read error or partial read packet. */
- if (ret < 0)
- goto done;
-
- /* Get size and type. */
- stream_forward_getp (peer->ibuf, BGP_MARKER_SIZE);
- memcpy (notify_data_length, stream_pnt (peer->ibuf), 2);
- size = stream_getw (peer->ibuf);
- type = stream_getc (peer->ibuf);
-
- if (BGP_DEBUG (normal, NORMAL) && type != 2 && type != 0)
- zlog_debug ("%s rcv message type %d, length (excl. header) %d",
- peer->host, type, size - BGP_HEADER_SIZE);
-
- /* Marker check */
- if (((type == BGP_MSG_OPEN) || (type == BGP_MSG_KEEPALIVE))
- && ! bgp_marker_all_one (peer->ibuf, BGP_MARKER_SIZE))
- {
- bgp_notify_send (peer,
- BGP_NOTIFY_HEADER_ERR,
- BGP_NOTIFY_HEADER_NOT_SYNC);
- goto done;
- }
-
- /* BGP type check. */
- if (type != BGP_MSG_OPEN && type != BGP_MSG_UPDATE
- && type != BGP_MSG_NOTIFY && type != BGP_MSG_KEEPALIVE
- && type != BGP_MSG_ROUTE_REFRESH_NEW
- && type != BGP_MSG_ROUTE_REFRESH_OLD
- && type != BGP_MSG_CAPABILITY)
- {
- if (BGP_DEBUG (normal, NORMAL))
- plog_debug (peer->log,
- "%s unknown message type 0x%02x",
- peer->host, type);
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_HEADER_ERR,
- BGP_NOTIFY_HEADER_BAD_MESTYPE,
- &type, 1);
- goto done;
- }
- /* Mimimum packet length check. */
- if ((size < BGP_HEADER_SIZE)
- || (size > BGP_MAX_PACKET_SIZE)
- || (type == BGP_MSG_OPEN && size < BGP_MSG_OPEN_MIN_SIZE)
- || (type == BGP_MSG_UPDATE && size < BGP_MSG_UPDATE_MIN_SIZE)
- || (type == BGP_MSG_NOTIFY && size < BGP_MSG_NOTIFY_MIN_SIZE)
- || (type == BGP_MSG_KEEPALIVE && size != BGP_MSG_KEEPALIVE_MIN_SIZE)
- || (type == BGP_MSG_ROUTE_REFRESH_NEW && size < BGP_MSG_ROUTE_REFRESH_MIN_SIZE)
- || (type == BGP_MSG_ROUTE_REFRESH_OLD && size < BGP_MSG_ROUTE_REFRESH_MIN_SIZE)
- || (type == BGP_MSG_CAPABILITY && size < BGP_MSG_CAPABILITY_MIN_SIZE))
- {
- if (BGP_DEBUG (normal, NORMAL))
- plog_debug (peer->log,
- "%s bad message length - %d for %s",
- peer->host, size,
- type == 128 ? "ROUTE-REFRESH" :
- bgp_type_str[(int) type]);
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_HEADER_ERR,
- BGP_NOTIFY_HEADER_BAD_MESLEN,
- (u_char *) notify_data_length, 2);
- goto done;
- }
-
- /* Adjust size to message length. */
- peer->packet_size = size;
- }
-
- ret = bgp_read_packet (peer);
- if (ret < 0)
- goto done;
-
- /* Get size and type again. */
- size = stream_getw_from (peer->ibuf, BGP_MARKER_SIZE);
- type = stream_getc_from (peer->ibuf, BGP_MARKER_SIZE + 2);
-
- /* BGP packet dump function. */
- bgp_dump_packet (peer, type, peer->ibuf);
-
- size = (peer->packet_size - BGP_HEADER_SIZE);
-
- /* Read rest of the packet and call each sort of packet routine */
- switch (type)
- {
- case BGP_MSG_OPEN:
- peer->open_in++;
- bgp_open_receive (peer, size); /* XXX return value ignored! */
- break;
- case BGP_MSG_UPDATE:
- peer->readtime = time(NULL); /* Last read timer reset */
- bgp_update_receive (peer, size);
- break;
- case BGP_MSG_NOTIFY:
- bgp_notify_receive (peer, size);
- break;
- case BGP_MSG_KEEPALIVE:
- peer->readtime = time(NULL); /* Last read timer reset */
- bgp_keepalive_receive (peer, size);
- break;
- case BGP_MSG_ROUTE_REFRESH_NEW:
- case BGP_MSG_ROUTE_REFRESH_OLD:
- peer->refresh_in++;
- bgp_route_refresh_receive (peer, size);
- break;
- case BGP_MSG_CAPABILITY:
- peer->dynamic_cap_in++;
- bgp_capability_receive (peer, size);
- break;
- }
+ int cp;
- /* Clear input buffer. */
- peer->packet_size = 0;
- if (peer->ibuf)
- stream_reset (peer->ibuf);
+ /* Preserve current pointer. */
+ cp = stream_get_endp (s);
+ stream_putw_at (s, BGP_MARKER_SIZE, cp);
- done:
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
- {
- if (BGP_DEBUG (events, EVENTS))
- zlog_debug ("%s [Event] Accepting BGP peer delete", peer->host);
- peer_delete (peer);
- }
- return 0;
-}
+ return cp;
+} ;
diff --git a/bgpd/bgp_msg_write.h b/bgpd/bgp_msg_write.h
index 8f0ebe31..68891a67 100644
--- a/bgpd/bgp_msg_write.h
+++ b/bgpd/bgp_msg_write.h
@@ -1,57 +1,55 @@
-/* BGP packet management header.
- Copyright (C) 1999 Kunihiro Ishiguro
-
-This file is part of GNU Zebra.
-
-GNU Zebra is free software; you can redistribute it and/or modify it
-under the terms of the GNU General Public License as published by the
-Free Software Foundation; either version 2, or (at your option) any
-later version.
-
-GNU Zebra is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Zebra; see the file COPYING. If not, write to the Free
-Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
-
-#ifndef _QUAGGA_BGP_PACKET_H
-#define _QUAGGA_BGP_PACKET_H
-
-#define BGP_NLRI_LENGTH 1U
-#define BGP_TOTAL_ATTR_LEN 2U
-#define BGP_UNFEASIBLE_LEN 2U
-#define BGP_WRITE_PACKET_MAX 10U
-
-/* When to refresh */
-#define REFRESH_IMMEDIATE 1
-#define REFRESH_DEFER 2
-
-/* ORF Common part flag */
-#define ORF_COMMON_PART_ADD 0x00
-#define ORF_COMMON_PART_REMOVE 0x80
-#define ORF_COMMON_PART_REMOVE_ALL 0xC0
-#define ORF_COMMON_PART_PERMIT 0x00
-#define ORF_COMMON_PART_DENY 0x20
-
-/* Packet send and receive function prototypes. */
-extern int bgp_read (struct thread *);
-extern int bgp_write (struct thread *);
-
-extern void bgp_keepalive_send (struct peer *);
-extern void bgp_open_send (struct peer *);
-extern void bgp_notify_send (struct peer *, u_int8_t, u_int8_t);
-extern void bgp_notify_send_with_data (struct peer *, u_int8_t, u_int8_t,
- u_int8_t *, size_t);
-extern void bgp_route_refresh_send (struct peer *, afi_t, safi_t, u_char, u_char, int);
-extern void bgp_capability_send (struct peer *, afi_t, safi_t, int, int);
-extern void bgp_default_update_send (struct peer *, struct attr *,
- afi_t, safi_t, struct peer *);
-extern void bgp_default_withdraw_send (struct peer *, afi_t, safi_t);
-
-extern int bgp_capability_receive (struct peer *, bgp_size_t);
-
-#endif /* _QUAGGA_BGP_PACKET_H */
+/* BGP message writing -- in BGP Engine -- header
+ * Copyright (C) 1999 Kunihiro Ishiguro
+ *
+ * Recast for pthreaded bgpd: Copyright (C) 2009 Chris Hall (GMCH), Highwayman
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _QUAGGA_BGP_MSG_WRITE_H
+#define _QUAGGA_BGP_MSG_WRITE_H
+
+#include <stdint.h>
+
+#include "bgpd/bgp_common.h"
+#include "bgpd/bgp_connection.h"
+#include "bgpd/bgp_notification.h"
+#include "bgpd/bgp_open_state.h"
+#include "bgpd/bgp_route_refresh.h"
+
+#include "lib/stream.h"
+
+extern int
+bgp_msg_write_notification(bgp_connection connection, bgp_notify notification) ;
+
+extern int
+bgp_msg_send_keepalive(bgp_connection connection) ;
+
+extern int
+bgp_msg_send_open(bgp_connection connection, bgp_open_state open_state) ;
+
+extern int
+bgp_msg_send_route_refresh(bgp_connection connection, bgp_route_refresh rr) ;
+
+extern int
+bgp_packet_set_marker(struct stream *s, uint8_t type) ;
+
+extern int
+bgp_packet_set_size (struct stream *s) ;
+
+#endif /* _QUAGGA_BGP_MSG_WRITE_H */
diff --git a/bgpd/bgp_notification.c b/bgpd/bgp_notification.c
index 3f6ecad9..bd52d516 100644
--- a/bgpd/bgp_notification.c
+++ b/bgpd/bgp_notification.c
@@ -21,7 +21,11 @@
* Boston, MA 02111-1307, USA.
*/
+#include <string.h>
+
+#include "lib/zassert.h"
#include "lib/memory.h"
+
#include "bgpd/bgp_notification.h"
/*==============================================================================
@@ -100,7 +104,7 @@ bgp_notify_dup(bgp_notify notification)
extern void
bgp_notify_set(bgp_notify* p_dst, bgp_notify src)
{
- bgp_notify_free(*p_dst) ;
+ bgp_notify_free(p_dst) ;
*p_dst = src ;
} ;
@@ -125,7 +129,7 @@ bgp_notify_set_dup(bgp_notify* p_dst, bgp_notify src)
extern void
bgp_notify_set_mov(bgp_notify* p_dst, bgp_notify* p_src)
{
- bgp_notify_free(*p_dst) ;
+ bgp_notify_free(p_dst) ;
*p_dst = *p_src ;
*p_src = NULL ;
} ;
@@ -145,10 +149,13 @@ bgp_notify_free(bgp_notify* p_notification)
/*==============================================================================
* Append data to given notification
*
+ * Copes with zero length append.
+ *
* NB: returns possibly NEW ADDRESS of the notification.
*/
extern bgp_notify
-bgp_notify_append_data(bgp_notify notification, void* data, bgp_size_t len)
+bgp_notify_append_data(bgp_notify notification, const void* data,
+ bgp_size_t len)
{
bgp_size_t new_length = notification->length + len ;
@@ -156,12 +163,15 @@ bgp_notify_append_data(bgp_notify notification, void* data, bgp_size_t len)
{
bgp_size_t size = bgp_notify_size(new_length) ;
notification = XREALLOC(MTYPE_BGP_NOTIFY, notification, size) ;
- memset((void*)notification + notification->size, 0,
+ memset((char*)notification + notification->size, 0,
size - notification->size) ;
notification->size = size ;
} ;
- memcpy((void*)(notification->data) + notification->length, data, len) ;
+ if (len > 0)
+ memcpy((char*)(notification->data) + notification->length, data, len) ;
notification->length = new_length ;
+
+ return notification ;
} ;
diff --git a/bgpd/bgp_notification.h b/bgpd/bgp_notification.h
index 72608534..b9670e8a 100644
--- a/bgpd/bgp_notification.h
+++ b/bgpd/bgp_notification.h
@@ -24,6 +24,7 @@
#ifndef _QUAGGA_BGP_NOTIFY_H
#define _QUAGGA_BGP_NOTIFY_H
+#include <stddef.h>
#include "bgpd/bgp_common.h"
#ifndef Inline
@@ -36,111 +37,6 @@
typedef unsigned char bgp_nom_code_t ;
typedef unsigned char bgp_nom_subcode_t ;
-#ifndef _GMCH_BGP_H
-
-/* Notification Message Error Codes...........................................*/
-enum BGP_NOMC
-{
- BGP_NOMC_UNDEF = 0, /* Nothing defined for this code */
-
- BGP_NOMC_HEADER = 1, /* Message Header Error */
- BGP_NOMC_OPEN = 2, /* Open Message Error */
- BGP_NOMC_UPDATE = 3, /* Update Message Error */
- BGP_NOMC_HOLD_EXP = 4, /* Hold timer expired */
- BGP_NOMC_FSM = 5, /* Finite State Machine Error */
- BGP_NOMC_CEASE = 6, /* Cease RFC4486 */
-
- BGP_NOMC_MAX = 6 /* max known error code */
-} ;
-
-/* Notification Message Error Subcodes........................................*/
-
-enum BGP_NOMS
-{
- BGP_NOMS_UNSPECIFIC = 0 /* If nothing else applies */
-};
-
-enum BGP_NOMS_HEADER /* BGP_NOMC_HEADER subcodes */
-{
- BGP_NOMS_H_NOT_SYNC = 1, /* Connection Not Synchronised */
- /* (Marker field not all = 1,'s !) */
- BGP_NOMS_H_BAD_LEN = 2, /* Bad Message Length */
- /* DATA: the length that failed */
- BGP_NOMS_H_BAD_TYPE = 3, /* Bad Message Type */
- /* DATA: the message type objected to */
-
- BGP_NOMS_H_MAX = 3, /* max known subcode */
-} ;
-
-enum BGP_NOMS_OPEN /* BGP_NOMC_OPEN subcodes */
-{
- BGP_NOMS_O_VERSION = 1, /* Unsupported Version Number */
- /* DATA: largest supported version */
- BGP_NOMS_O_BAD_AS = 2, /* Bad Peer AS */
- BGP_NOMS_O_BAD_ID = 3, /* Bad BGP Identifier */
- BGP_NOMS_O_OPTION = 4, /* Unsupported Optional Parameter */
- BGP_NOMS_O_AUTH = 5, /* Authentication Failure (depr.) */
- BGP_NOMS_O_H_TIME = 6, /* Unacceptable Hold Time */
-
- BGP_NOMS_O_CAPABILITY = 7, /* Unsupported Capability RFC5492 */
- /* DATA: the unsupported capabilities */
-
- BGP_NOMS_O_MAX = 7, /* max known subcode */
-} ;
-
-enum BGP_NOMS_UPDATE /* BGP_NOMC_UPDATE subcodes */
-{
- BGP_NOMS_U_A_LIST = 1, /* Malformed Attribute List */
- /* (Attribute repeated) */
- BGP_NOMS_U_UNKNOWN = 2, /* Unrecognised Well-known Attrib */
- /* DATA: erroneous attribute */
- BGP_NOMS_U_MISSING = 3, /* Missing Well-known Attrib. */
- /* DATA: type of missing attribute(s?) */
- BGP_NOMS_U_A_FLAGS = 4, /* Attribute Flags Error */
- /* DATA: erroneous attribute */
- BGP_NOMS_U_A_LENGTH = 5, /* Attribute Length Error */
- /* DATA: erroneous attribute */
- BGP_NOMS_U_ORIGIN = 6, /* Invalid Origin Attribute */
- /* DATA: erroneous attribute */
- BGP_NOMS_U_AS_LOOP = 7, /* AS Routeing Loop (deprecated) */
- BGP_NOMS_U_NEXT_HOP = 8, /* Invalid NEXT_HOP Attrib. */
- /* DATA: erroneous attribute */
- BGP_NOMS_U_OPTIONAL = 9, /* Optional Attribute Error */
- /* DATA: erroneous attribute */
- BGP_NOMS_U_NETWORK = 10, /* Invalid Network Field */
- /* (badly formed NLRI) */
- BGP_NOMS_U_AS_PATH = 11, /* Malformed AS Path */
-
- BGP_NOMS_U_MAX = 11, /* max known subcode */
-} ;
-
-enum BGP_NOMS_HOLD_EXP /* BGP_NOMC_HOLD_EXP subcodes */
-{
- BGP_NOMS_HE_MAX = 0 /* max known subcode */
-} ;
-
-enum BGP_NOMC_FSM /* BGP_NOMC_FSM subcodes */
-{
- BGP_NOMS_F_MAX = 0 /* max known subcode */
-} ;
-
-enum BGP_NOMS_CEASE /* BGP_NOMC_CEASE subcodes RFC4486 */
-{
- BGP_NOMS_C_MAX_PREF = 1, /* Max Number of Prefixes Reached MUST */
- /* DATA: MAY be: AFI/SAFI/Upper-Bound */
- BGP_NOMS_C_SHUTDOWN = 2, /* Administrative Shutdown SHOULD */
- BGP_NOMS_C_DECONFIG = 3, /* Peer De-configured SHOULD */
- BGP_NOMS_C_RESET = 4, /* Administrative Reset SHOULD */
- BGP_NOMS_C_REJECTED = 5, /* Connection Rejected SHOULD */
- BGP_NOMS_C_CONFIG = 6, /* Other Configuration Change SHOULD */
- BGP_NOMS_C_COLLISION = 7, /* Connection Collision Res. SHOULD */
- BGP_NOMS_C_RESOURCES = 8, /* Out of Resources MAY */
-
- BGP_NOMS_C_MAX = 8 /* max known subcode */
-} ;
-
-#endif
-
/*==============================================================================
*
*/
@@ -259,7 +155,8 @@ bgp_notify_set_subcode(bgp_notify notification, bgp_nom_subcode_t subcode)
} ;
extern bgp_notify
-bgp_notify_append_data(bgp_notify notification, void* data, bgp_size_t len) ;
+bgp_notify_append_data(bgp_notify notification, const void* data,
+ bgp_size_t len) ;
Inline bgp_nom_code_t
diff --git a/bgpd/bgp_open_state.c b/bgpd/bgp_open_state.c
index 4c44bbd5..55d3b345 100644
--- a/bgpd/bgp_open_state.c
+++ b/bgpd/bgp_open_state.c
@@ -46,12 +46,19 @@ bgp_open_state_init_new(bgp_open_state state)
else
memset(state, 0, sizeof(struct bgp_open_state)) ;
+ vector_init_new(&state->unknowns, 0) ;
+
return state ;
}
bgp_open_state
bgp_open_state_free(bgp_open_state state)
{
+ bgp_cap_unknown unknown ;
+
+ while ((unknown = vector_ream_keep(&state->unknowns)) != NULL)
+ XFREE(MTYPE_TMP, unknown) ;
+
if (state != NULL)
XFREE(MTYPE_BGP_OPEN_STATE, state) ;
return NULL ;
@@ -87,8 +94,10 @@ bgp_peer_open_state_init_new(bgp_open_state state, bgp_peer peer)
/* Set our bgpd_id */
state->bgp_id = peer->local_id ;
- /* TODO: can_capability? */
- state->can_capability = 0;
+ /* Do not send capability. */ /* TODO: can_capability? */
+ state->can_capability =
+ CHECK_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN)
+ && (! CHECK_FLAG(peer->flags, PEER_FLAG_DONT_CAPABILITY) ) ;
/* Announce self as AS4 speaker if required */
state->can_as4 = ((peer->cap & PEER_CAP_AS4_ADV) != 0) ;
@@ -122,11 +131,14 @@ bgp_peer_open_state_init_new(bgp_open_state state, bgp_peer peer)
? (bgp_cap_form_old | bgp_cap_form_new)
: bgp_cap_form_none ;
+ /* Dynamic Capabilities TODO: check requirement */
+ state->can_dynamic = ( CHECK_FLAG(peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY)
+ != 0 ) ;
+
/* Graceful restart capability */
- /* TODO: check that support graceful restart for all supported AFI/SAFI */
if (bgp_flag_check(peer->bgp, BGP_FLAG_GRACEFUL_RESTART))
{
- state->can_g_restart = state->can_mp_ext ;
+ state->can_g_restart = 1 ;
state->restart_time = peer->bgp->restart_time ;
}
else
@@ -136,12 +148,60 @@ bgp_peer_open_state_init_new(bgp_open_state state, bgp_peer peer)
} ;
/* TODO: check not restarting and not preserving forwarding state (?) */
- state->can_nsf = 0 ;
- state->restarting = 0 ;
+ state->can_preserve = 0 ; /* cannot preserve forwarding */
+ state->has_preserved = 0 ; /* has not preserved forwarding */
+ state->restarting = 0 ; /* is not restarting */
return state;
}
+/*==============================================================================
+ * Unknown capabilities handling.
+ *
+ */
+
+/*------------------------------------------------------------------------------
+ * Add given unknown capability and its value to the given open_state.
+ */
+extern void
+bgp_open_state_unknown_add(bgp_open_state state, uint8_t code,
+ void* value, bgp_size_t length)
+{
+ bgp_cap_unknown unknown ;
+
+ unknown = XCALLOC(MTYPE_TMP, sizeof(struct bgp_cap_unknown) + length) ;
+
+ unknown->code = code ;
+ unknown->length = length ;
+
+ if (length != 0)
+ memcpy(unknown->value, value, length) ;
+
+ vector_push_item(&state->unknowns, unknown) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Get count of number of unknown capabilities in given open_state.
+ */
+extern void
+bgp_open_state_unknown_count(bgp_open_state state)
+{
+ return vector_end(&state->unknowns) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Get n'th unknown capability -- if exists.
+ */
+extern bgp_cap_unknown
+bgp_open_state_unknown_cap(bgp_open_state state, unsigned index)
+{
+ return vector_get_item(&state->unknowns, index) ;
+} ;
+
+/*==============================================================================
+ *
+ */
+
/* Received an open, update the peer's state */
void
bgp_peer_open_state_receive(bgp_peer peer)
diff --git a/bgpd/bgp_open_state.h b/bgpd/bgp_open_state.h
index 534dcadf..c67e0108 100644
--- a/bgpd/bgp_open_state.h
+++ b/bgpd/bgp_open_state.h
@@ -22,8 +22,11 @@
#ifndef _QUAGGA_BGP_OPEN_STATE_H
#define _QUAGGA_BGP_OPEN_STATE_H
-#include "bgpd/bgp_common.h"
+#include <stdint.h>
+#include "bgpd/bgp.h"
+#include "bgpd/bgp_common.h"
+#include "lib/vector.h"
#ifndef Inline
#define Inline static inline
@@ -40,7 +43,8 @@ enum bgp_cap_form
{
bgp_cap_form_none = 0,
bgp_cap_form_old = 1,
- bgp_cap_form_new = 2
+ bgp_cap_form_new = 2,
+ bgp_cap_form_both = 3 /* _old and _new are bits ! */
} ;
/*==============================================================================
@@ -51,6 +55,14 @@ enum bgp_cap_form
*
*/
+typedef struct bgp_cap_unknown* bgp_cap_unknown ;
+struct bgp_cap_unknown /* to capture unknown capability */
+{
+ uint8_t code ;
+ bgp_size_t length ;
+ uint8_t value[] ;
+} ;
+
struct bgp_open_state
{
as_t my_as ; /* generic ASN */
@@ -63,18 +75,22 @@ struct bgp_open_state
qafx_set_t can_mp_ext ; /* will accept, may send these */
- bgp_cap_form_t can_r_refresh ; /* none/old/new */
- bgp_cap_form_t can_orf_prefix ; /* none/old/new */
+ bgp_cap_form_t can_r_refresh ; /* none/old/new/both */
+ bgp_cap_form_t can_orf_prefix ; /* none/old/new/both */
qafx_set_t can_orf_prefix_send ; /* wish to send ORF Prefix-List */
qafx_set_t can_orf_prefix_recv ; /* will accept ORF Prefix-List */
- qafx_set_t can_g_restart ; /* will gracefully restart these */
- qafx_set_t can_nsf ; /* will preserve forwarding state */
+ int can_dynamic ;
+
+ int can_g_restart ; /* can do graceful restart */
+ qafx_set_t can_preserve ; /* can preserve forwarding for these */
+ qafx_set_t has_preserved ; /* has preserved forwarding for these */
int restarting ; /* Restart State flag */
int restart_time ; /* Restart Time in seconds */
+ struct vector unknowns ; /* list of bgp_cap_unknown */
} ;
/*==============================================================================
@@ -87,6 +103,15 @@ bgp_open_state_init_new(bgp_open_state state) ;
extern bgp_open_state
bgp_open_state_free(bgp_open_state state) ;
+extern void
+bgp_open_state_unknown_add(bgp_open_state state, uint8_t code,
+ void* value, bgp_size_t length) ;
+extern void
+bgp_open_state_unknown_count(bgp_open_state state) ;
+
+extern bgp_cap_unknown
+bgp_open_state_unknown_cap(bgp_open_state state, unsigned index) ;
+
extern bgp_open_state
bgp_peer_open_state_init_new(bgp_open_state state, bgp_peer peer);
diff --git a/bgpd/bgp_packet.h b/bgpd/bgp_packet.h
index 8f0ebe31..8be95f40 100644
--- a/bgpd/bgp_packet.h
+++ b/bgpd/bgp_packet.h
@@ -28,14 +28,16 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
/* When to refresh */
#define REFRESH_IMMEDIATE 1
-#define REFRESH_DEFER 2
+#define REFRESH_DEFER 2
/* ORF Common part flag */
-#define ORF_COMMON_PART_ADD 0x00
-#define ORF_COMMON_PART_REMOVE 0x80
-#define ORF_COMMON_PART_REMOVE_ALL 0xC0
-#define ORF_COMMON_PART_PERMIT 0x00
-#define ORF_COMMON_PART_DENY 0x20
+#define ORF_COMMON_PART_ADD 0x00
+/* TODO: BUG REPORT... ORF_COMMON_PART_REMOVE should be 0x40 ! */
+#define ORF_COMMON_PART_REMOVE 0x80
+/* TODO: BUG REPORT... ORF_COMMON_PART_REMOVE_ALL should be 0x80 ! */
+#define ORF_COMMON_PART_REMOVE_ALL 0xC0
+#define ORF_COMMON_PART_PERMIT 0x00
+#define ORF_COMMON_PART_DENY 0x20
/* Packet send and receive function prototypes. */
extern int bgp_read (struct thread *);
@@ -44,7 +46,7 @@ extern int bgp_write (struct thread *);
extern void bgp_keepalive_send (struct peer *);
extern void bgp_open_send (struct peer *);
extern void bgp_notify_send (struct peer *, u_int8_t, u_int8_t);
-extern void bgp_notify_send_with_data (struct peer *, u_int8_t, u_int8_t,
+extern void bgp_notify_send_with_data (struct peer *, u_int8_t, u_int8_t,
u_int8_t *, size_t);
extern void bgp_route_refresh_send (struct peer *, afi_t, safi_t, u_char, u_char, int);
extern void bgp_capability_send (struct peer *, afi_t, safi_t, int, int);
diff --git a/bgpd/bgp_route_refresh.c b/bgpd/bgp_route_refresh.c
new file mode 100644
index 00000000..d50f977b
--- /dev/null
+++ b/bgpd/bgp_route_refresh.c
@@ -0,0 +1,186 @@
+/* BGP ROUTE-REFRESH and ORF handling
+ * Copyright (C) Chris Hall (GMCH), Highwayman
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+
+#include "lib/zassert.h"
+#include "lib/memory.h"
+#include "lib/vector.h"
+
+#include "bgpd/bgp_route_refresh.h"
+
+/*==============================================================================
+ * A bgp_route_refresh structure encapsulates the contents of a BGP
+ * ROUTE-REFRESH message, with or without ORF part.
+ *
+ * For incoming messages, expect a bgp_route_refresh structure to be the
+ * contents of a single ROUTE-REFRESH message.
+ *
+ * For outgoing messages, a bgp_route_refresh structure may contain a large
+ * number of ORF entries, and those are carved up into as many ROUTE-REFRESH
+ * messages as required.
+ */
+
+/*==============================================================================
+ * Create/Destroy bgp_route_refresh
+ */
+
+/*------------------------------------------------------------------------------
+ * Allocate and initialise new bgp_route_refresh
+ *
+ * Constructs complete simple ROUTE-REFRESH -- ORF stuff can then be added.
+ *
+ * Can specify an expected number of ORF entries (need not be actual number).
+ */
+extern bgp_route_refresh
+bgp_route_refresh_new(iAFI_t afi, iSAFI_t safi, unsigned count)
+{
+ bgp_route_refresh rr ;
+
+ rr = XCALLOC(MTYPE_BGP_ROUTE_REFRESH, sizeof(struct bgp_route_refresh)) ;
+
+ rr->afi = afi ;
+ rr->safi = safi ;
+
+ vector_init_new(&rr->entries, count) ;
+
+ /* rest of bgp_route_refresh zeroised -- not relevant when vector empty */
+
+ return rr ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Free bgp_route_refresh
+ */
+extern void
+bgp_route_refresh_free(bgp_route_refresh rr)
+{
+ bgp_orf_entry entry ;
+ while((entry = vector_ream_keep(&rr->entries)) != NULL)
+ XFREE(MTYPE_BGP_ORF_ENTRY, entry) ;
+
+ XFREE(MTYPE_BGP_ROUTE_REFRESH, rr) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Allocate new bgp_orf_entry -- for known or unknown type.
+ *
+ * Is for known type if unknown_size == 0 !
+ *
+ * Sets orf_type and unknown elements of the entry.
+ *
+ * NB: it is a FATAL error to set an unknown ORF type unless is explicitly
+ * unknown ! (In this context "pre-RFC" types are unknown.)
+ *
+ * Zeroises rest of structure -- in particular remove_all == false !
+ *
+ * Pushes entry onto the bgp_route_refresh list.
+ */
+static bgp_orf_entry
+bgp_orf_entry_new(bgp_route_refresh rr, uint8_t orf_type, size_t unknown_size)
+{
+ bgp_orf_entry orfe ;
+ size_t e_size ;
+
+ if (unknown_size == 0)
+ {
+ if (orf_type != BGP_ORF_T_PREFIX)
+ zabort("unknown ORF type") ;
+ e_size = 0 ;
+ }
+ else
+ {
+ if (unknown_size < bgp_orf_unknown_min_l)
+ e_size = 0 ;
+ else
+ e_size = unknown_size - bgp_orf_unknown_min_l ;
+ } ;
+
+ orfe = XCALLOC(MTYPE_BGP_ORF_ENTRY, sizeof(struct bgp_orf_entry) + e_size) ;
+
+ orfe->orf_type = orf_type ;
+ orfe->unknown = (unknown_size != 0) ;
+
+ vector_push_item(&rr->entries, orfe) ;
+
+ return orfe ;
+} ;
+
+/*==============================================================================
+ * Creating new ORF entries.
+ */
+
+/*------------------------------------------------------------------------------
+ * Add an entry for known type of ORF.
+ *
+ * Sets the common ORF entry part.
+ *
+ * Returns address of the ORF type specific structure, to be filled in.
+ *
+ * The orf_type presented must be a known BGP_ORF_T_xxx value, EXCLUDING any
+ * "pre-RFC" types. (Any use of pre-RFC values is looked after at the message
+ * level).
+ *
+ * NB: it is a FATAL error to set an unknown ORF type
+ */
+extern void*
+bgp_orf_add(bgp_route_refresh rr, uint8_t orf_type, flag_t remove, flag_t deny)
+{
+ bgp_orf_entry orfe = bgp_orf_entry_new(rr, orf_type, 0) ;
+
+ orfe->remove = (remove != 0) ;
+ orfe->deny = (deny != 0) ;
+
+ return &orfe->body ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Add a remove_all entry.
+ *
+ * The orf_type presented must be a known BGP_ORF_T_xxx value, EXCLUDING any
+ * "pre-RFC" types. (Any use of pre-RFC values is looked after at the message
+ * level).
+ *
+ * NB: it is a FATAL error to set an unknown ORF type
+ */
+extern void
+bgp_orf_add_remove_all(bgp_route_refresh rr, uint8_t orf_type)
+{
+ bgp_orf_entry orfe = bgp_orf_entry_new(rr, orf_type, 0) ;
+
+ orfe->remove_all = 1 ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Add an entry for an unknown type of ORF -- copy the entry verbatim.
+ *
+ * Provided so that can capture entire contents of incoming message.
+ */
+extern void
+bgp_orf_add_unknown(bgp_route_refresh rr, uint8_t orf_type, bgp_size_t length,
+ const void* entries)
+{
+ bgp_orf_entry orfe = bgp_orf_entry_new(rr, orf_type,
+ (length > 0) ? length : 1) ;
+
+ if (length != 0)
+ memcpy(&orfe->body.orf_unknown.data, entries, length) ;
+} ;
diff --git a/bgpd/bgp_route_refresh.h b/bgpd/bgp_route_refresh.h
new file mode 100644
index 00000000..8ac6059b
--- /dev/null
+++ b/bgpd/bgp_route_refresh.h
@@ -0,0 +1,135 @@
+/* BGP ROUTE-REFRESH and ORF handling -- header
+ * Copyright (C) Chris Hall (GMCH), Highwayman
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _QUAGGA_BGP_ROUTE_REFRESH_H
+#define _QUAGGA_BGP_ROUTE_REFRESH_H
+
+#include <stddef.h>
+#include "bgpd/bgp_common.h"
+
+#include "lib/prefix.h"
+
+#ifndef Inline
+#define Inline static inline
+#endif
+
+
+/*==============================================================================
+ * Structures to hold ROUTE-REFRESH and ORF
+ */
+
+typedef struct bgp_orf_prefix_entry* bgp_orf_prefix_entry ;
+struct bgp_orf_prefix_entry
+{
+ uint32_t seq ;
+ uint8_t min ;
+ uint8_t max ;
+
+ struct prefix pfx ;
+} ;
+
+typedef struct bgp_orf_unknown_entry* bgp_orf_unknown_entry ;
+struct bgp_orf_unknown_entry
+{
+ bgp_size_t length ;
+ uint8_t data[] ;
+} ;
+
+typedef struct bgp_orf_entry* bgp_orf_entry ;
+struct bgp_orf_entry
+{
+ uint8_t orf_type ; /* BGP_ORF_T_xxx */
+
+ flag_t unknown ; /* ignore everything other than the */
+ /* unknown data part */
+
+ flag_t remove_all ; /* rest is ignored if this is set */
+
+ flag_t remove ; /* otherwise: add */
+ flag_t deny ; /* otherwise: permit */
+
+ union { /* must be last... */
+ struct bgp_orf_prefix_entry orf_prefix ;
+ struct bgp_orf_unknown_entry orf_unknown ; /*... flexible array. */
+ } body ;
+} ;
+
+typedef struct bgp_orf_entry bgp_orf_entry_t ; /* calm down Eclipse */
+enum
+{
+ bgp_orf_unknown_min_l = sizeof(struct bgp_orf_entry)
+ - offsetof(bgp_orf_entry_t, body.orf_unknown.data)
+} ;
+
+typedef struct bgp_route_refresh* bgp_route_refresh ;
+struct bgp_route_refresh
+{
+ iAFI_t afi ; /* NB: Internet AFI/SAFI */
+ iSAFI_t safi ;
+
+ struct vector entries ; /* empty => simple ROUTE-REFRESH */
+
+ flag_t defer ; /* otherwise: immediate */
+
+ /* These support the output of ROUTE-REFRESH messages.
+ *
+ * These are zeroised when the bgp_route_refresh stucture is created.
+ */
+ unsigned next ; /* next entry to process */
+ uint8_t last_orf_type ; /* type of last ORF entry processed */
+} ;
+
+/*==============================================================================
+ * Prototypes
+ */
+
+extern bgp_route_refresh
+bgp_route_refresh_new(iAFI_t afi, iSAFI_t safi, unsigned count) ;
+
+extern void
+bgp_route_refresh_set_orf_defer(bgp_route_refresh rr, flag_t defer) ;
+
+extern void
+bgp_route_refresh_free(bgp_route_refresh rr) ;
+
+extern void*
+bgp_orf_add(bgp_route_refresh rr, uint8_t orf_type, flag_t remove, flag_t deny);
+
+extern void
+bgp_orf_add_remove_all(bgp_route_refresh rr, uint8_t orf_type) ;
+
+extern void
+bgp_orf_add_unknown(bgp_route_refresh rr, uint8_t orf_type, bgp_size_t length,
+ const void* entries) ;
+
+Inline unsigned
+bgp_orf_get_count(bgp_route_refresh rr)
+{
+ return vector_end(&rr->entries) ;
+} ;
+
+Inline bgp_orf_entry
+bgp_orf_get_entry(bgp_route_refresh rr, unsigned index)
+{
+ return vector_get_item(&rr->entries, index) ;
+} ;
+
+#endif /* _QUAGGA_BGP_ROUTE_REFRESH_H */
diff --git a/bgpd/bgp_session.c b/bgpd/bgp_session.c
index 214829ef..dbf6c5ca 100644
--- a/bgpd/bgp_session.c
+++ b/bgpd/bgp_session.c
@@ -115,6 +115,9 @@ bgp_session_init_new(bgp_session session, bgp_peer peer)
* connect -- unset, false
* listen -- unset, false
*
+ * cap_override -- unset, false
+ * cap_strict -- unset, false
+ *
* ttl -- unset
* port -- unset
* su_peer -- NULL -- none
@@ -130,6 +133,7 @@ bgp_session_init_new(bgp_session session, bgp_peer peer)
* keepalive_timer_interval )
*
* as4 -- unset, false
+ * route_refresh_pre -- unset, false
*
* su_local -- NULL -- none
* su_remote -- NULL -- none
diff --git a/bgpd/bgp_session.h b/bgpd/bgp_session.h
index 416a1876..b84fca04 100644
--- a/bgpd/bgp_session.h
+++ b/bgpd/bgp_session.h
@@ -112,7 +112,7 @@ struct bgp_session
* session was ever established.
*/
bgp_session_state_t state ;
- int made ; /* set when -> sEstablished */
+ flag_t made ; /* set when -> sEstablished */
/* The BGP Engine records the last event, NOTIFICATION and errno here.
*
@@ -138,8 +138,11 @@ struct bgp_session
/* The following are set by the Routeing Engine before a session is
* enabled, and not changed at any other time by either engine.
*/
- int connect ; /* initiate connections */
- int listen ; /* listen for connections */
+ flag_t connect ; /* initiate connections */
+ flag_t listen ; /* listen for connections */
+
+ flag_t cap_override ; /* override ... TODO: what ? */
+ flag_t cap_strict ; /* strict... TODO: what ? */
int ttl ; /* TTL to set, if not zero */
unsigned short port ; /* destination port for peer */
@@ -155,7 +158,7 @@ struct bgp_session
unsigned open_hold_timer_interval ;
/* These are set by the Routeing Engine before a session is enabled,
- * and may be changed by the BGP Engine when the session is established.
+ * but are affected by the capabilities received in the OPEN message.
*
* The Routeing Engine may read these once sEstablished (under mutex).
*
@@ -164,7 +167,8 @@ struct bgp_session
unsigned hold_timer_interval ; /* subject to negotiation */
unsigned keepalive_timer_interval ; /* subject to negotiation */
- int as4 ;
+ flag_t as4 ; /* set by OPEN */
+ flag_t route_refresh_pre ; /* use pre-RFC version */
/* These are cleared by the Routeing Engine before a session is enabled,
* and set by the BGP Engine when the session is established.
diff --git a/lib/Makefile.am b/lib/Makefile.am
index d6d3022a..c11d1959 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -31,7 +31,7 @@ pkginclude_HEADERS = \
privs.h sigevent.h pqueue.h jhash.h zassert.h memtypes.h \
workqueue.h route_types.h symtab.h heap.h \
qtime.h qpthreads.h mqueue.h qpselect.h qtimers.h qpnexus.h \
- command_queue.h qlib_init.h qafi_safi.h
+ command_queue.h qlib_init.h qafi_safi.h confirm.h
EXTRA_DIST = regex.c regex-gnu.h memtypes.awk route_types.awk route_types.txt
diff --git a/lib/confirm.h b/lib/confirm.h
new file mode 100644
index 00000000..caccf742
--- /dev/null
+++ b/lib/confirm.h
@@ -0,0 +1,28 @@
+/* Compile time CONFIRM gizmo
+ * Copyright (C) 2009 Chris Hall (GMCH), Highwayman
+ *.
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+/*==============================================================================
+ * Compile time CONFIRM gizmo
+ *
+ * Two forms: CONFIRM(e) for use at top (file) level
+ * confirm(e) for use inside compound statements
+ */
+#ifndef CONFIRM
+
+ #define CONFIRM(e) extern void CONFIRMATION(char CONFIRM[(e) ? 1 : -1]) ;
+ #define confirm(e) { CONFIRM(e) }
+
+#endif
diff --git a/lib/memtypes.c b/lib/memtypes.c
index 7c4c6f61..96dd8f4a 100644
--- a/lib/memtypes.c
+++ b/lib/memtypes.c
@@ -119,6 +119,8 @@ struct memory_list memory_list_bgp[] =
{ MTYPE_BGP_SESSION, "BGP session" },
{ MTYPE_BGP_CONNECTION, "BGP connection" },
{ MTYPE_BGP_NOTIFY, "BGP notification" },
+ { MTYPE_BGP_ROUTE_REFRESH, "BGP route refresh" },
+ { MTYPE_BGP_ORF_ENTRY, "BGP ORF entry" },
{ MTYPE_ATTR, "BGP attribute" },
{ MTYPE_ATTR_EXTRA, "BGP extra attributes" },
{ MTYPE_AS_PATH, "BGP aspath" },
diff --git a/lib/stream.c b/lib/stream.c
index 36bbba1e..dc636361 100644
--- a/lib/stream.c
+++ b/lib/stream.c
@@ -236,6 +236,20 @@ stream_set_getp (struct stream *s, size_t pos)
s->getp = pos;
}
+void
+stream_set_endp (struct stream *s, size_t pos)
+{
+ STREAM_VERIFY_SANE(s);
+
+ if (!ENDP_VALID (s, pos))
+ {
+ STREAM_BOUND_WARN (s, "set endp");
+ return ;
+ }
+
+ s->endp = pos;
+}
+
/* Forward pointer. */
void
stream_forward_getp (struct stream *s, size_t size)
diff --git a/lib/stream.h b/lib/stream.h
index 4c8a4fa9..957bf495 100644
--- a/lib/stream.h
+++ b/lib/stream.h
@@ -147,6 +147,7 @@ extern size_t stream_get_size (struct stream *);
extern u_char *stream_get_data (struct stream *);
extern void stream_set_getp (struct stream *, size_t);
+extern void stream_set_endp (struct stream *, size_t);
extern void stream_forward_getp (struct stream *, size_t);
extern void stream_forward_endp (struct stream *, size_t);
diff --git a/lib/zassert.h b/lib/zassert.h
index 424688b9..a766eb7b 100644
--- a/lib/zassert.h
+++ b/lib/zassert.h
@@ -5,6 +5,8 @@
#ifndef _QUAGGA_ASSERT_H
#define _QUAGGA_ASSERT_H
+#include "confirm.h"
+
extern void _zlog_assert_failed (const char *assertion, const char *file,
unsigned int line, const char *function)
__attribute__ ((noreturn));
@@ -61,17 +63,4 @@ extern void _zlog_abort_err (const char *mess, int err, const char *file,
#define zabort_err(MS, ERR) _zlog_abort_err(MS, ERR, __FILE__, __LINE__, \
__ASSERT_FUNCTION)
-/*==============================================================================
- * Compile time CONFIRM gizmo
- *
- * Two forms: CONFIRM(e) for use at top (file) level
- * confirm(e) for use inside compound statements
- */
-#ifndef CONFIRM
-
- #define CONFIRM(e) extern void CONFIRMATION(char CONFIRM[(e) ? 1 : -1]) ;
- #define confirm(e) { CONFIRM(e) }
-
-#endif
-
#endif /* _QUAGGA_ASSERT_H */