summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp.h6
-rw-r--r--bgpd/bgp_common.c12
-rw-r--r--bgpd/bgp_common.h53
-rw-r--r--bgpd/bgp_connection.c18
-rw-r--r--bgpd/bgp_connection.h8
-rw-r--r--bgpd/bgp_fsm.c34
-rw-r--r--bgpd/bgp_fsm.h3
-rw-r--r--bgpd/bgp_msg_read.c717
-rw-r--r--bgpd/bgp_msg_read.h3
-rw-r--r--bgpd/bgp_msg_write.c38
-rw-r--r--bgpd/bgp_notification.c17
-rw-r--r--bgpd/bgp_notification.h3
-rw-r--r--bgpd/bgp_open_state.c70
-rw-r--r--bgpd/bgp_open_state.h61
-rw-r--r--bgpd/bgp_route_refresh.c28
-rw-r--r--bgpd/bgp_route_refresh.h28
-rw-r--r--lib/qafi_safi.h5
17 files changed, 833 insertions, 271 deletions
diff --git a/bgpd/bgp.h b/bgpd/bgp.h
index 3bcabd8e..9edf51f4 100644
--- a/bgpd/bgp.h
+++ b/bgpd/bgp.h
@@ -574,8 +574,8 @@ enum /* order */
BGP_RRM_AFI,
BGP_RRM_RES,
BGP_RRM_SAFI,
- BGP_RRM_ORF_WHEN, /* start of ORF message */
- BGP_RRM_ORFS, /* start of ORF collections */
+ BGP_RRM_ORF_WHEN, /* start of ORF message */
+ BGP_RRM_ORFS, /* start of ORF collections -- *one* or more */
} ;
enum /* values for the BGP_RRM_ORF_WHEN byte */
@@ -584,7 +584,7 @@ enum /* values for the BGP_RRM_ORF_WHEN byte */
BGP_ORF_WTR_DEFER = 2 /* when-to-refresh == defer */
} ;
-/* ORFS come in collections...................................................*/
+/* ORFS come in collections -- one or more....................................*/
typedef U8 BGP_ORF_TYPE_T ; /* ORF Type */
typedef U16 BGP_ORF_LEN_T ; /* length of ORF entries: octets */
diff --git a/bgpd/bgp_common.c b/bgpd/bgp_common.c
index 90281ff5..8b2b6cea 100644
--- a/bgpd/bgp_common.c
+++ b/bgpd/bgp_common.c
@@ -62,6 +62,7 @@ qafx_num(qafx_bit_t bit)
/*==============================================================================
* Conversion tables for qafx_num => qAFI and qSAFI
* and qafx_num => iAFI and iSAFI
+ * and qafx_num => pAF
*/
const qAFI_t qAFI_map[] =
@@ -108,6 +109,17 @@ const iSAFI_t iSAFI_map[] =
[qafx_num_other] = iSAFI_Reserved,
} ;
+const pAF_t pAF_map[] =
+ {
+ [qafx_ipv4_unicast] = AF_INET,
+ [qafx_ipv4_multicast] = AF_INET,
+ [qafx_ipv4_mpls_vpn] = AF_INET,
+ [qafx_ipv6_unicast] = AF_INET6,
+ [qafx_ipv6_multicast] = AF_INET6,
+ [qafx_ipv6_mpls_vpn] = AF_INET6,
+ [qafx_num_other] = AF_UNSPEC,
+ } ;
+
/*==============================================================================
* Convert iAFI/iSAFI => qafx_num_t -- tolerates unknown/reserved
* and qAFI/qSAFI => qafx_num_t -- tolerates undef, but not unknown
diff --git a/bgpd/bgp_common.h b/bgpd/bgp_common.h
index a2722ed1..703b2ab2 100644
--- a/bgpd/bgp_common.h
+++ b/bgpd/bgp_common.h
@@ -23,6 +23,8 @@
#define _QUAGGA_BGP_COMMON_H
#include <stdint.h>
+#include <sys/socket.h>
+
#include "bgpd/bgp.h"
#include "qafi_safi.h"
#include "lib/zassert.h"
@@ -54,6 +56,22 @@ typedef struct bgp_connection* bgp_connection ;
typedef struct bgp_open_state* bgp_open_state ;
/*==============================================================================
+ * Some BGP capabilities and messages have RFC and pre-RFC forms.
+ *
+ * Sometimes see both, or send RFC and/or pre-RFC forms, or track what form(s)
+ * are being used.
+ */
+typedef enum bgp_form bgp_form_t ;
+
+enum bgp_form
+{
+ bgp_form_none = 0,
+ bgp_form_pre = 1,
+ bgp_form_rfc = 2,
+ bgp_form_both = 3 /* _rfc and _pre are bits ! */
+} ;
+
+/*==============================================================================
* Both session and connection require these
*/
@@ -206,7 +224,7 @@ extern qafx_num_t
qafx_num(qafx_bit_t bit) ;
/*==============================================================================
- * Conversions for qafx_num => qAFI and qSAFI
+ * Conversions for qafx_num => qAFI, qSAFI, iAFI, iSAFI and pAF
*/
/*------------------------------------------------------------------------------
@@ -281,6 +299,24 @@ get_iSAFI(qafx_num_t num)
return iSAFI_map[num] ;
} ;
+/*------------------------------------------------------------------------------
+ * Convert qafx_num_t to AF_xxx (pAF_t)
+ *
+ * Maps qafx_num_other to iSAFI_Reserved.
+ *
+ * NB: it is a mistake to try to map qafx_num_undef (FATAL unless NDEBUG).
+ */
+
+extern const pAF_t pAF_map[] ;
+
+Inline pAF_t
+get_pAF(qafx_num_t num)
+{
+ dassert((num >= qafx_num_min) && (num <= qafx_num_max)) ;
+
+ return pAF_map[num] ;
+} ;
+
/*==============================================================================
* Conversions for iAFI/iSAFI => qafx_num_t
* and qAFI/qSAFI => qafx_num_t
@@ -302,6 +338,12 @@ extern qafx_bit_t
qafx_bit_from_qAFI_qSAFI(qAFI_t afi, qSAFI_t safi) ;
/*==============================================================================
+ *
+ */
+
+
+
+/*==============================================================================
* Buffer sucking
*
*
@@ -344,6 +386,15 @@ suck_start(sucker sr)
return sr->start ;
} ;
+Inline ptr_t
+suck_step(sucker sr, unsigned length)
+{
+ ptr_t ptr = sr->ptr ;
+ sr->ptr += length ;
+ dassert(sr->ptr <= sr->end) ;
+ return ptr ;
+} ;
+
Inline void
suck_push(sucker sr, unsigned length, sucker sv)
{
diff --git a/bgpd/bgp_connection.c b/bgpd/bgp_connection.c
index 5915b57f..c7935cf3 100644
--- a/bgpd/bgp_connection.c
+++ b/bgpd/bgp_connection.c
@@ -248,8 +248,8 @@ bgp_connection_make_primary(bgp_connection connection)
session->keepalive_timer_interval = connection->keepalive_timer_interval ;
session->as4 = connection->as4 ;
- session->route_refresh_pre = connection->route_refresh_pre ;
- session->orf_prefix_pre = connection->orf_prefix_pre ;
+ session->route_refresh_pre = connection->route_refresh ;
+ session->orf_prefix_pre = connection->orf_prefix ;
sockunion_set_mov(&session->su_local, &connection->su_local) ;
sockunion_set_mov(&session->su_remote, &connection->su_remote) ;
@@ -902,7 +902,7 @@ bgp_connection_read_action(qps_file qf, void* file_info)
*
* Exits loop iff completes a BGP message.
*/
- while (want > 0)
+ while (1)
{
ret = stream_read_nonblock(connection->ibuf, qps_file_fd(&connection->qf),
want) ;
@@ -922,6 +922,8 @@ bgp_connection_read_action(qps_file qf, void* file_info)
want = bgp_msg_check_header(connection) ;
/* returns balance of message */
+ if (want == 0)
+ break ;
}
else
{
@@ -930,11 +932,11 @@ bgp_connection_read_action(qps_file qf, void* file_info)
} ;
} ;
- if (want < 0)
- return ; /* failed in header check */
-
- /* Deal with the BGP message. MUST remove from ibuf before returns ! */
- bgp_msg_dispatch(connection) ;
+ /* Deal with the BGP message. MUST remove from ibuf before returns !
+ *
+ * NB: size passed is the size of the *body* of the message.
+ */
+ connection->msg_func(connection, connection->msg_body_size) ;
/* Ready to read another message */
connection->read_pending = 0 ;
diff --git a/bgpd/bgp_connection.h b/bgpd/bgp_connection.h
index 24762646..d38be299 100644
--- a/bgpd/bgp_connection.h
+++ b/bgpd/bgp_connection.h
@@ -36,6 +36,7 @@
#include "bgpd/bgp_session.h"
#include "bgpd/bgp_open_state.h"
#include "bgpd/bgp_notification.h"
+#include "bgpd/bgp_msg_read.h"
#ifndef Inline
#define Inline static inline
@@ -161,8 +162,8 @@ struct bgp_connection
unsigned keepalive_timer_interval ; /* subject to negotiation */
flag_t as4 ; /* subject to negotiation */
- flag_t route_refresh_pre ; /* subject to negotiation */
- flag_t orf_prefix_pre ; /* subject to negotiation */
+ flag_t route_refresh ; /* subject to negotiation */
+ flag_t orf_prefix ; /* subject to negotiation */
struct qtimer hold_timer ;
struct qtimer keepalive_timer ;
@@ -172,7 +173,8 @@ struct bgp_connection
flag_t read_header ; /* reading message header */
uint8_t msg_type ; /* copy of message type */
- bgp_size_t msg_size ; /* size of message *body* */
+ bgp_size_t msg_body_size ; /* size of message *body* */
+ bgp_msg_handler* msg_func ; /* function to handle message */
struct stream* obuf ; /* a single output "stream" */
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index 88916948..e4152f80 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -673,7 +673,7 @@ static void
bgp_fsm_throw_exception(bgp_connection connection, bgp_session_event_t except,
bgp_notify notification, int err, bgp_fsm_event_t event)
{
- bgp_fsm_post_exception(connection, except,notification, err) ;
+ bgp_fsm_post_exception(connection, except, notification, err) ;
bgp_fsm_event(connection, event) ;
} ;
@@ -693,6 +693,35 @@ bgp_fsm_post_catch(bgp_connection connection, bgp_session_event_t except,
} ;
/*==============================================================================
+ * Signal that have received a message that is some form of "update".
+ *
+ * If is established: re-charge the HoldTimer.
+ *
+ * otherwise: raise bfp_fsm_eUpdate event, which will most likely
+ * throw an error.
+ *
+ * Avoids going through the full FSM process for update events (of which there
+ * may be many) in the simple case -- where only need to re-charge HoldTimer.
+ *
+ * Deals, via the FSM, with unexpected "update" events -- for example an
+ * UPDATE (or ROUTE-REFRESH) before reaching sEstablished !
+ */
+static void bgp_hold_timer_recharge(bgp_connection connection) ;
+
+extern int
+bgp_fsm_pre_update(bgp_connection connection)
+{
+ if (connection->state == bgp_fsm_sEstablished)
+ {
+ bgp_hold_timer_recharge(connection) ;
+ return 0 ;
+ } ;
+
+ bgp_fsm_event(connection, bgp_fsm_eReceive_UPDATE_message) ;
+ return -1 ;
+} ;
+
+/*==============================================================================
* For debug...
*/
#define BGP_FSM_DEBUG(connection, message) \
@@ -1643,9 +1672,6 @@ bgp_fsm_event(bgp_connection connection, bgp_fsm_event_t event)
static void
bgp_hold_timer_set(bgp_connection connection, unsigned secs) ;
-static void
-bgp_hold_timer_recharge(bgp_connection connection) ;
-
static bgp_fsm_state_t
bgp_fsm_send_notification(bgp_connection connection,
bgp_fsm_state_t next_state) ;
diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h
index bbf9ebca..49a4bef9 100644
--- a/bgpd/bgp_fsm.h
+++ b/bgpd/bgp_fsm.h
@@ -33,6 +33,9 @@ bgp_fsm_enable_session(bgp_session session) ;
extern void
bgp_fsm_disable_session(bgp_session session, bgp_notify notification) ;
+extern int
+bgp_fsm_pre_update(bgp_connection connection) ;
+
extern void
bgp_fsm_event(bgp_connection connection, bgp_fsm_event_t event) ;
diff --git a/bgpd/bgp_msg_read.c b/bgpd/bgp_msg_read.c
index aa6ee64d..640126e0 100644
--- a/bgpd/bgp_msg_read.c
+++ b/bgpd/bgp_msg_read.c
@@ -29,25 +29,31 @@
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_session.h"
#include "bgpd/bgp_open_state.h"
+#include "bgpd/bgp_route_refresh.h"
#include "bgpd/bgp_fsm.h"
#include "bgpd/bgp_vty.h"
+/*------------------------------------------------------------------------------
+ * Message handler functions.
+ */
+static void bgp_msg_unknown_receive(bgp_connection connection,
+ bgp_size_t body_size) ;
+static void bgp_msg_open_receive(bgp_connection connection,
+ bgp_size_t body_size) ;
+static void bgp_msg_update_receive(bgp_connection connection,
+ bgp_size_t body_size) ;
+static void bgp_msg_notify_receive(bgp_connection connection,
+ bgp_size_t body_size) ;
+static void bgp_msg_keepalive_receive(bgp_connection connection,
+ bgp_size_t body_size) ;
+static void bgp_msg_route_refresh_receive(bgp_connection connection,
+ bgp_size_t body_size) ;
+static void bgp_msg_capability_receive(bgp_connection connection,
+ bgp_size_t body_size) ;
-
-/* prototypes */
-static int bgp_msg_open_receive (bgp_connection connection, bgp_size_t size);
-static int bgp_msg_update_receive (bgp_connection connection, bgp_size_t size);
-static int bgp_msg_keepalive_receive (bgp_connection connection,
- bgp_size_t size);
-static void bgp_msg_notify_receive (bgp_connection connection, bgp_size_t size);
-static void bgp_msg_notify_send (bgp_connection connection, bgp_session_event_t except,
- bgp_nom_code_t code, bgp_nom_subcode_t sub_code);
-static void bgp_msg_notify_send_with_data (bgp_connection connection,
- bgp_session_event_t except, bgp_nom_code_t code, bgp_nom_subcode_t sub_code,
- u_char *data, size_t datalen);
-
-
-/* Get BGP message length, given a pointer to the start of a message */
+/*------------------------------------------------------------------------------
+ * Get BGP message length, given a pointer to the start of a message
+ */
extern bgp_size_t
bgp_msg_get_mlen(uint8_t* p)
{
@@ -55,9 +61,22 @@ bgp_msg_get_mlen(uint8_t* p)
} ;
-/*------------------------------------------------------------------------------
- * Header validation support.
+/*==============================================================================
+ * Header validation and sexing of messages
*/
+enum
+{
+ qBGP_MT_unknown = 0,
+ qBGP_MT_OPEN,
+ qBGP_MT_UPDATE,
+ qBGP_MT_NOTIFICATION,
+ qBGP_MT_KEEPALIVE,
+ qBGP_MT_ROUTE_REFRESH,
+ qBGP_MT_CAPABILITY,
+ qBGP_MT_ROUTE_REFRESH_pre,
+
+ qBGP_MT_count,
+} ;
/* 0 1 2 3 */
static const uint8_t bgp_header[] = { 0xFF, 0xFF, 0xFF, 0xFF, /* 4 */
0xFF, 0xFF, 0xFF, 0xFF, /* 8 */
@@ -66,19 +85,60 @@ static const uint8_t bgp_header[] = { 0xFF, 0xFF, 0xFF, 0xFF, /* 4 */
} ;
CONFIRM(sizeof(bgp_header) == BGP_MH_MARKER_L) ;
-/* Array to return minimum message length.
- *
- * Length includes the header, so cannot possibly be zero !
- */
-static const bgp_size_t bgp_type_min_size[256] =
+/* Array to map real BGP message type to qBGP message type */
+static const uint8_t bgp_type_map[256] =
{
- [BGP_MT_OPEN] = BGP_OPM_MIN_L,
- [BGP_MT_UPDATE] = BGP_UPM_MIN_L,
- [BGP_MT_NOTIFICATION] = BGP_NOM_MIN_L,
- [BGP_MT_KEEPALIVE] = BGP_KAM_L,
- [BGP_MT_ROUTE_REFRESH] = BGP_RRM_MIN_L,
- [BGP_MT_CAPABILITY] = BGP_MH_HEAD_L, /* pro tem */
- [BGP_MT_ROUTE_REFRESH_pre] = BGP_RRM_MIN_L
+ [BGP_MT_OPEN] = qBGP_MT_OPEN,
+ [BGP_MT_UPDATE] = qBGP_MT_UPDATE,
+ [BGP_MT_NOTIFICATION] = qBGP_MT_NOTIFICATION,
+ [BGP_MT_KEEPALIVE] = qBGP_MT_KEEPALIVE,
+ [BGP_MT_ROUTE_REFRESH] = qBGP_MT_ROUTE_REFRESH,
+ [BGP_MT_CAPABILITY] = qBGP_MT_CAPABILITY,
+ [BGP_MT_ROUTE_REFRESH_pre] = qBGP_MT_ROUTE_REFRESH_pre
+} ;
+CONFIRM(qBGP_MT_unknown == 0) ;
+
+/* Array of minimum message length -- by qBGP_MT_xxx */
+static const bgp_size_t bgp_type_min_size[] =
+{
+ [qBGP_MT_unknown] = BGP_MSG_MAX_L + 1, /* invalid ! */
+
+ [qBGP_MT_OPEN] = BGP_OPM_MIN_L,
+ [qBGP_MT_OPEN] = BGP_OPM_MIN_L,
+ [qBGP_MT_UPDATE] = BGP_UPM_MIN_L,
+ [qBGP_MT_NOTIFICATION] = BGP_NOM_MIN_L,
+ [qBGP_MT_KEEPALIVE] = BGP_KAM_L,
+ [qBGP_MT_ROUTE_REFRESH] = BGP_RRM_MIN_L,
+ [qBGP_MT_CAPABILITY] = BGP_MH_HEAD_L, /* pro tem */
+ [qBGP_MT_ROUTE_REFRESH_pre] = BGP_RRM_MIN_L
+} ;
+
+/* Array of message handler functions -- by qBGP_MT_xxx */
+static bgp_msg_handler* const bgp_type_handler[] =
+{
+ [qBGP_MT_unknown] = bgp_msg_unknown_receive,
+
+ [qBGP_MT_OPEN] = bgp_msg_open_receive,
+ [qBGP_MT_UPDATE] = bgp_msg_update_receive,
+ [qBGP_MT_NOTIFICATION] = bgp_msg_notify_receive,
+ [qBGP_MT_KEEPALIVE] = bgp_msg_keepalive_receive,
+ [qBGP_MT_ROUTE_REFRESH] = bgp_msg_keepalive_receive,
+ [qBGP_MT_CAPABILITY] = bgp_msg_capability_receive,
+ [qBGP_MT_ROUTE_REFRESH_pre] = bgp_msg_route_refresh_receive
+} ;
+
+/* Array of message type names by qBGP_MT_xxxx */
+static const char* bgp_type_name[] =
+{
+ [qBGP_MT_unknown] = "*unknown*",
+
+ [qBGP_MT_OPEN] = "OPEN",
+ [qBGP_MT_UPDATE] = "UPDATE",
+ [qBGP_MT_NOTIFICATION] = "NOTIFICATION",
+ [qBGP_MT_KEEPALIVE] = "KEEPALIVE",
+ [qBGP_MT_ROUTE_REFRESH] = "ROUTE-REFRESH",
+ [qBGP_MT_CAPABILITY] = "CAPABILITY",
+ [qBGP_MT_ROUTE_REFRESH_pre] = "ROUTE-REFRESH(pre)"
} ;
/*------------------------------------------------------------------------------
@@ -86,7 +146,7 @@ static const bgp_size_t bgp_type_min_size[256] =
*
* Issue notification and kick FSM.
*/
-static int
+static void
bgp_msg_header_bad_len(bgp_connection connection, uint8_t type, bgp_size_t size)
{
uint16_t notify_size = htons(size) ;
@@ -95,12 +155,34 @@ bgp_msg_header_bad_len(bgp_connection connection, uint8_t type, bgp_size_t size)
plog_debug (connection->log,
"%s bad message length - %d for %s",
connection->host, size,
- type == 128 ? "ROUTE-REFRESH" : bgp_type_str[(int) type]) ;
+ bgp_type_name[bgp_type_map[type]]) ;
- bgp_msg_notify_send_with_data (connection, bgp_session_eInvalid_msg,
- BGP_NOMC_HEADER, BGP_NOMS_H_BAD_LEN,
- (void*)&notify_size, 2) ;
- return -1 ;
+ bgp_fsm_raise_exception(connection, bgp_session_eInvalid_msg,
+ bgp_notify_new_with_data(BGP_NOMC_HEADER, BGP_NOMS_H_BAD_LEN,
+ (void*)&notify_size, 2)) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * The message type is either unknown, or not enabled by capability exchange.
+ *
+ * Issue notification and kick FSM.
+ */
+static void
+bgp_msg_header_bad_type(bgp_connection connection, uint8_t type)
+{
+ if (BGP_DEBUG (normal, NORMAL))
+ {
+ if (bgp_type_map[type] == qBGP_MT_unknown)
+ plog_debug (connection->log, "%s unknown message type 0x%02x",
+ connection->host, type) ;
+ else
+ plog_err (connection->log, "%s [Error] BGP %s is not enabled",
+ connection->host, bgp_type_name[bgp_type_map[type]]) ;
+ } ;
+
+ bgp_fsm_raise_exception(connection, bgp_session_eInvalid_msg,
+ bgp_notify_new_with_data(BGP_NOMC_HEADER, BGP_NOMS_H_BAD_TYPE,
+ (void*)&type, 1)) ;
} ;
/*------------------------------------------------------------------------------
@@ -112,19 +194,29 @@ bgp_msg_header_bad_len(bgp_connection connection, uint8_t type, bgp_size_t size)
*
* Advances the stream getp past the header.
*
- * Plants: msg_type -- the message type
- * msg_size -- the size of the message body
+ * Plants: msg_type -- the message type
+ * msg_body_size -- the size of the message *body*
+ * msg_func -- the function to process the message
*
* in the connection, ready for bgp_msg_dispatch().
*
- * return >= 0 number of bytes still to read (ie msg_size)
- * return -1 error
+ * Returns: number of bytes still to read (ie msg_body_size) -- may be 0
+ *
+ * NB: deals with invalid header, unknown message type and less than minimum
+ * message length for the message type.
+ *
+ * These all raise the required events, and return with minimum size
+ * message and the function set to bgp_msg_unknown_receive.
+ *
+ * The effect is that the reader will not read any more, and will dispatch
+ * to bgp_msg_unknown_receive.
*/
int
bgp_msg_check_header(bgp_connection connection)
{
uint8_t type ;
bgp_size_t size ;
+ uint8_t qt ;
bgp_size_t min_size ;
/* Get size and type. */
@@ -138,89 +230,56 @@ bgp_msg_check_header(bgp_connection connection)
/* Marker check */
/* TODO: why did old code only do this on OPEN and KEEPALIVE ? */
- if (memcmp(connection->ibuf->data, bgp_header, BGP_MH_MARKER_L) != 0)
+ if (memcmp(connection->ibuf->data, bgp_header, BGP_MH_MARKER_L) == 0)
{
- bgp_msg_notify_send (connection, bgp_session_eInvalid_msg,
- BGP_NOTIFY_HEADER_ERR,
- BGP_NOTIFY_HEADER_NOT_SYNC);
- return -1;
- } ;
+ /* BGP type check and minimum/maximum message length checks. */
- /* BGP type check. */
- min_size = bgp_type_min_size[type] ;
+ qt = bgp_type_map[type] ; /* qBGP_MT_unknown if not valid */
+ min_size = bgp_type_min_size[qt] ;/* > BGP_MSG_MAX_L if not valid */
- if (min_size == 0)
+ if ((size < min_size) || (size > BGP_MSG_MAX_L))
+ {
+ if (qt == qBGP_MT_unknown)
+ {
+ if (BGP_DEBUG (normal, NORMAL))
+ plog_debug (connection->log, "%s unknown message type 0x%02x",
+ connection->host, type);
+
+ bgp_fsm_raise_exception(connection, bgp_session_eInvalid_msg,
+ bgp_notify_new_with_data(BGP_NOMC_HEADER, BGP_NOMS_H_BAD_TYPE,
+ (void*)&type, 1)) ;
+ }
+ else
+ bgp_msg_header_bad_len(connection, type, size) ;
+
+ size = BGP_MH_HEAD_L ; /* can stop reading, now */
+ }
+ }
+ else
{
- if (BGP_DEBUG (normal, NORMAL))
- plog_debug (connection->log,
- "%s unknown message type 0x%02x",
- connection->host, type);
-
- bgp_msg_notify_send_with_data (connection, bgp_session_eInvalid_msg,
- BGP_NOMC_HEADER,
- BGP_NOMS_H_BAD_TYPE,
- &type, 1);
- return -1;
+ bgp_fsm_raise_exception(connection, bgp_session_eInvalid_msg,
+ bgp_notify_new(BGP_NOMC_HEADER, BGP_NOMS_H_NOT_SYNC, 0)) ;
+ qt = qBGP_MT_unknown ; /* force unknown message */
+ size = BGP_MH_HEAD_L ; /* can stop reading, now */
} ;
- /* Mimimum and maximum message length checks. */
- if ((size < min_size) || (size > BGP_MSG_MAX_L))
- return bgp_msg_header_bad_len(connection, type, size) ;
- connection->msg_type = type ;
- connection->msg_size = size - BGP_MH_HEAD_L ;
+ connection->msg_type = type ;
+ connection->msg_body_size = size - BGP_MH_HEAD_L ;
+ connection->msg_func = bgp_type_handler[qt] ;
- return connection->msg_size ;
-}
+ return connection->msg_body_size ;
+} ;
-/*------------------------------------------------------------------------------
- * Dispatch BGP message.
- *
- * Arrives in the connection->ibuf, with the getp sitting after the message
- * header. Also:
- *
- * connection->msg_type -- type
- * connection->msg_size -- size of message body (excludes header)
+/*==============================================================================
+ * Invalid message handler.
*
- * Must have finished with ibuf when returns.
+ * Does nothing at all -- the error has already been deal with, this just
+ * allows unknown (and invalid) messages to be handled just like OK ones.
*/
-void
-bgp_msg_dispatch(bgp_connection connection)
+static void bgp_msg_unknown_receive(bgp_connection connection, bgp_size_t body_size)
{
- bgp_size_t size = connection->msg_size ;
-
- switch (connection->msg_type)
- {
- case BGP_MT_OPEN:
- bgp_msg_open_receive (connection, size);
- break;
- case BGP_MT_UPDATE:
- bgp_msg_update_receive (connection, size);
- break;
- case BGP_MT_NOTIFICATION:
- bgp_msg_notify_receive(connection, size);
- break;
- case BGP_MT_KEEPALIVE:
- bgp_msg_keepalive_receive(connection, size);
- break;
- case BGP_MT_ROUTE_REFRESH:
- case BGP_MT_ROUTE_REFRESH_pre:
- /* TODO: refresh? */
-#if 0
- peer->refresh_in++;
- bgp_route_refresh_receive (peer, size);
-#endif
- break;
- case BGP_MT_CAPABILITY:
- /* TODO: dynamic capability? */
-#if 0
- peer->dynamic_cap_in++;
- bgp_capability_receive (peer, size);
-#endif
- break;
- default:
- assert(0); /* types already validated */
- } ;
+ return ;
} ;
/*==============================================================================
@@ -245,11 +304,9 @@ bgp_msg_open_invalid(bgp_notify notification) ;
/*------------------------------------------------------------------------------
* Receive BGP open packet and parse it into the connection's open_recv
*
- * return 0 OK
- * return -1 error
*/
-static int
-bgp_msg_open_receive (bgp_connection connection, bgp_size_t size)
+static void
+bgp_msg_open_receive (bgp_connection connection, bgp_size_t body_size)
{
int ret;
u_char version;
@@ -438,21 +495,19 @@ bgp_msg_open_receive (bgp_connection connection, bgp_size_t size)
connection->hold_timer_interval = holdtime ;
connection->keepalive_timer_interval = holdtime / 3 ;
- connection->as4 = open_recv->can_as4 ;
- connection->route_refresh_pre = open_recv->can_r_refresh == bgp_cap_form_old;
- connection->orf_prefix_pre = open_recv->can_orf_prefix == bgp_cap_form_old;
+ connection->as4 = open_recv->can_as4 ;
+ connection->route_refresh = open_recv->can_r_refresh ;
+ connection->orf_prefix = open_recv->can_orf_prefix ;
bgp_fsm_event(connection, bgp_fsm_eReceive_OPEN_message) ;
- return 0;
+ return ;
/*............................................................................
* Failed. Reject the OPEN with the required notification.
*/
reject:
bgp_fsm_raise_exception(connection, bgp_session_eOpen_reject, notification);
-
- return -1 ;
} ;
/*------------------------------------------------------------------------------
@@ -845,11 +900,11 @@ bgp_msg_capability_option_parse (bgp_connection connection,
break;
case BGP_CAN_R_REFRESH:
- open_recv->can_r_refresh |= bgp_cap_form_new ;
+ open_recv->can_r_refresh |= bgp_form_rfc ;
break ;
case BGP_CAN_R_REFRESH_pre:
- open_recv->can_r_refresh |= bgp_cap_form_old;
+ open_recv->can_r_refresh |= bgp_form_pre;
break;
case BGP_CAN_ORF:
@@ -935,6 +990,7 @@ bgp_msg_capability_mp(bgp_connection connection, sucker sr)
{
struct iAFI_SAFI mp ;
qafx_bit_t qb ;
+ bgp_cap_afi_safi cap ;
qb = bgp_msg_afi_safi(sr, &mp) ;
@@ -942,6 +998,8 @@ bgp_msg_capability_mp(bgp_connection connection, sucker sr)
zlog_debug ("%s OPEN has MP_EXT CAP for afi/safi: %u/%u",
connection->host, mp.afi, mp.safi) ;
+ cap = bgp_open_state_afi_safi_add(connection->open_recv, mp.afi, mp.safi,
+ (qb != 0), BGP_CAN_MP_EXT) ;
if (qb == 0)
{
zlog_warn ("Unknown afi/safi combination (%u/%u)", mp.afi, mp.safi) ;
@@ -1015,6 +1073,7 @@ bgp_msg_capability_orf_entry(bgp_connection connection, uint8_t cap_code,
int number ;
int length ;
sucker_t ssr ;
+ bgp_cap_afi_safi cap ;
bgp_open_state open_recv = connection->open_recv ;
qafx_bit_t qb ;
@@ -1077,7 +1136,7 @@ bgp_msg_capability_orf_entry(bgp_connection connection, uint8_t cap_code,
switch (type)
{
case BGP_CAP_ORFT_T_PFIX:
- open_recv->can_orf_prefix |= bgp_cap_form_new ;
+ open_recv->can_orf_prefix |= bgp_form_rfc ;
qbs = qafx_ipv4_unicast_bit
| qafx_ipv4_multicast_bit
| qafx_ipv6_unicast_bit ;
@@ -1090,7 +1149,7 @@ bgp_msg_capability_orf_entry(bgp_connection connection, uint8_t cap_code,
switch (type)
{
case BGP_CAP_ORFT_T_PFIX_pre:
- open_recv->can_orf_prefix |= bgp_cap_form_old ;
+ open_recv->can_orf_prefix |= bgp_form_pre ;
qbs = qafx_ipv4_unicast_bit
| qafx_ipv4_multicast_bit
| qafx_ipv6_unicast_bit ;
@@ -1103,13 +1162,20 @@ bgp_msg_capability_orf_entry(bgp_connection connection, uint8_t cap_code,
break ;
} ;
+ cap = bgp_open_state_afi_safi_add(connection->open_recv, mp.afi, mp.safi,
+ (qb != 0), cap_code) ;
+ cap->caps.orf.known_orf_type = (qbs != 0) ;
+ cap->caps.orf.type = type ;
+ cap->caps.orf.send = ((mode & BGP_CAP_ORFT_M_SEND) != 0) ;
+ cap->caps.orf.recv = ((mode & BGP_CAP_ORFT_M_RECV) != 0) ;
+
if ((qbs & qb) == 0)
{
if (BGP_DEBUG (normal, NORMAL))
zlog_debug ("%s Addr-family %d/%d has"
" ORF type/mode %d/%d not supported",
connection->host, mp.afi, mp.safi, type, mode) ;
- continue;
+ continue ;
} ;
if (BGP_DEBUG (normal, NORMAL))
@@ -1140,7 +1206,7 @@ bgp_msg_capability_orf_entry(bgp_connection connection, uint8_t cap_code,
} ;
/*------------------------------------------------------------------------------
- * Process value of Graceful Restart -- BGP_CAN_G_RESTART -- RFC2918
+ * Process value of Graceful Restart capability -- BGP_CAN_G_RESTART -- RFC2918
*
* Capability is: time -- word
* AFI -- word )
@@ -1160,6 +1226,7 @@ bgp_msg_capability_restart (bgp_connection connection, sucker sr)
bgp_open_state open_recv = connection->open_recv;
u_int16_t restart_flag_time ;
int length ;
+ bgp_cap_afi_safi cap ;
length = suck_left(sr) ; /* total length of value, for reporting */
@@ -1200,12 +1267,18 @@ bgp_msg_capability_restart (bgp_connection connection, sucker sr)
iAFI_SAFI_t mp ;
uint8_t flags ;
qafx_bit_t qb ;
+ int has_preserved ;
mp.afi = suck_w(sr) ;
mp.safi = suck_b(sr) ;
flags = suck_b(sr) ;
qb = qafx_bit_from_iAFI_iSAFI(mp.afi, mp.safi) ;
+ has_preserved = ((flags & BGP_CAP_GRE_F_FORW) != 0) ;
+
+ cap = bgp_open_state_afi_safi_add(connection->open_recv, mp.afi, mp.safi,
+ (qb != 0), BGP_CAN_G_RESTART) ;
+ cap->caps.gr.has_preserved = has_preserved ;
if (qb == 0)
{
@@ -1220,20 +1293,14 @@ bgp_msg_capability_restart (bgp_connection connection, sucker sr)
if (connection->session->open_send->can_mp_ext & qb)
{
- qafx_bit_t has ;
- if (flags & BGP_CAP_GRE_F_FORW)
- has = qb ;
- else
- has = 0 ;
-
open_recv->can_preserve |= qb ;
- open_recv->has_preserved |= has ;
+ open_recv->has_preserved |= (has_preserved ? qb : 0) ;
if (BGP_DEBUG (normal, NORMAL))
zlog_debug ("%s Address family %s is%spreserved",
connection->host,
afi_safi_print (mp.afi, mp.safi),
- has ? " " : " not ") ;
+ (has_preserved ? " " : " not ")) ;
}
else
{
@@ -1277,69 +1344,369 @@ bgp_msg_capability_as4 (bgp_connection connection, sucker sr)
/*==============================================================================
* BGP UPDATE message
*/
-
-/* Parse BGP Update packet. */
-static int
-bgp_msg_update_receive (bgp_connection connection, bgp_size_t size)
+static void
+bgp_msg_update_receive (bgp_connection connection, bgp_size_t body_size)
{
- bgp_session_update_recv(connection->session, connection->ibuf, size);
- bgp_fsm_event(connection, bgp_fsm_eReceive_UPDATE_message);
- return 0;
+ /* Must be prepared to receive "update" like messages */
+ if (bgp_fsm_pre_update(connection) != 0) ;
+ {
+ plog_err(connection->log,
+ "%s [Error] Update message received while in %s State",
+ connection->host, LOOKUP(bgp_status_msg, connection->state)) ;
+ return ;
+ }
+
+ /* PRO TEM: pass raw update message across to Peering Engine */
+ /* TODO: decode update messages in the BGP Engine. */
+ bgp_session_update_recv(connection->session, connection->ibuf, body_size);
}
/*==============================================================================
* BGP KEEPALIVE message
*/
-static int
-bgp_msg_keepalive_receive (bgp_connection connection, bgp_size_t size)
+static void
+bgp_msg_keepalive_receive (bgp_connection connection, bgp_size_t body_size)
{
if (BGP_DEBUG (keepalive, KEEPALIVE))
zlog_debug ("%s KEEPALIVE rcvd", connection->host);
- if (size != 0)
- return bgp_msg_header_bad_len(connection, BGP_MT_KEEPALIVE, size) ;
-
- bgp_fsm_event(connection, bgp_fsm_eReceive_KEEPALIVE_message);
-
- return 0;
-}
+ if (body_size == 0)
+ bgp_fsm_event(connection, bgp_fsm_eReceive_KEEPALIVE_message);
+ else
+ bgp_msg_header_bad_len(connection, BGP_MT_KEEPALIVE, body_size) ;
+} ;
/*==============================================================================
* BGP NOTIFICATION message
*/
static void
-bgp_msg_notify_receive (bgp_connection connection, bgp_size_t size)
+bgp_msg_notify_receive (bgp_connection connection, bgp_size_t body_size)
{
- bgp_notify notification;
- bgp_nom_code_t code = stream_getc (connection->ibuf);
+ bgp_nom_code_t code = stream_getc (connection->ibuf);
bgp_nom_subcode_t subcode = stream_getc (connection->ibuf);
- bgp_size_t expect = size - 2;
- notification = bgp_notify_new(code, subcode, expect);
- bgp_notify_append_data(notification, stream_pnt(connection->ibuf), expect);
+ bgp_fsm_notification_exception(connection,
+ bgp_notify_new_with_data(code, subcode,
+ stream_pnt(connection->ibuf), body_size - 2)) ;
+} ;
- bgp_fsm_notification_exception(connection, notification);
-}
+/*==============================================================================
+ * BGP ROUTE-REFRESH message
+ */
+static int
+bgp_msg_orf_recv(bgp_connection connection, bgp_route_refresh rr,
+ qafx_bit_t qb, sucker sr) ;
+static int
+bgp_msg_orf_prefix_recv(orf_prefix orfpe, qafx_bit_t qb, sucker sr) ;
-/* Send BGP notify packet. */
+/*------------------------------------------------------------------------------
+ * Process BGP ROUTE-REFRESH message
+ *
+ * This may contain ORF stuff !
+ */
static void
-bgp_msg_notify_send (bgp_connection connection, bgp_session_event_t except,
- bgp_nom_code_t code, bgp_nom_subcode_t sub_code)
+bgp_msg_route_refresh_receive(bgp_connection connection, bgp_size_t body_size)
{
- bgp_notify notification;
- notification = bgp_notify_new(code, sub_code, 0);
- bgp_fsm_raise_exception(connection, except, notification);
-}
+ struct iAFI_SAFI mp ;
+ sucker_t ssr ;
+ qafx_bit_t qb ;
+ bgp_route_refresh rr ;
+ unsigned form ;
+ int ret ;
+ /* If peer does not have the capability, treat as bad message type */
-/* Send BGP notify packet with data portion. */
-static void
-bgp_msg_notify_send_with_data (bgp_connection connection,
- bgp_session_event_t except, bgp_nom_code_t code, bgp_nom_subcode_t sub_code,
- u_char *data, size_t datalen)
+ switch (connection->msg_type)
+ {
+ case BGP_MT_ROUTE_REFRESH:
+ form = bgp_form_rfc ;
+ break ;
+ case BGP_MT_ROUTE_REFRESH_pre:
+ form = bgp_form_pre ;
+ break ;
+ default: /* should not happen, really */
+ form = 0 ;
+ break ;
+ } ;
+
+ if ((connection->route_refresh & form) == 0)
+ {
+ bgp_msg_header_bad_type(connection, connection->msg_type) ;
+ return ;
+ } ;
+
+ /* Must be prepared to receive "update" like messages */
+ if (connection->state != bgp_fsm_sEstablished)
+ {
+ plog_err(connection->log,
+ "%s [Error] Route-Refresh message received while in %s State",
+ connection->host, LOOKUP(bgp_status_msg, connection->state)) ;
+ return ;
+ } ;
+
+ /* Set about parsing the message */
+
+ dassert(stream_get_left(connection->ibuf) == body_size) ;
+ suck_init(&ssr, stream_pnt(connection->ibuf), body_size) ;
+
+ /* Start with AFI, reserved, SAFI */
+ qb = bgp_msg_afi_safi(&ssr, &mp) ;
+
+ qb &= qafx_ipv4_unicast_bit | qafx_ipv4_multicast_bit |
+ qafx_ipv6_unicast_bit | qafx_ipv6_multicast_bit |
+ qafx_ipv4_mpls_vpn_bit ;
+
+ if (BGP_DEBUG (normal, NORMAL))
+ zlog_debug ("%s rcvd REFRESH_REQ for afi/safi: %d/%d%s",
+ connection->host, mp.afi, mp.safi,
+ (qb == 0) ? " -- unknown combination" : "") ;
+
+ rr = bgp_route_refresh_new(mp.afi, mp.safi, 0) ;
+
+ /* If there are any ORF entries, time to suck them up now. */
+ ret = 0 ;
+
+ if (suck_left(&ssr) != 0)
+ {
+ uint8_t when_to_refresh ;
+ flag_t defer = 0 ;
+
+ when_to_refresh = suck_b(&ssr) ;
+
+ switch (when_to_refresh)
+ {
+ case BGP_ORF_WTR_IMMEDIATE:
+ defer = 0 ;
+ break ;
+ case BGP_ORF_WTR_DEFER:
+ defer = 1 ;
+ break ;
+ default:
+ zlog_info ("%s ORF route refresh invalid 'when' value %d"
+ " (AFI/SAFI %d/%d)",
+ connection->host, when_to_refresh, rr->afi, rr->safi) ;
+ ret = -1 ;
+ break ;
+ } ;
+
+ if (ret >= 0)
+ {
+ bgp_route_refresh_set_orf_defer(rr, defer) ;
+
+ /* After the when to refresh, expect 1 or more ORFs */
+ do
+ {
+ ret = bgp_msg_orf_recv(connection, rr, qb, &ssr) ;
+ } while ((ret == 0) && (suck_left(&ssr) != 0)) ;
+ } ;
+ } ;
+
+ if (ret < 0)
+ {
+ bgp_fsm_raise_exception(connection, bgp_session_eInvalid_msg,
+ bgp_notify_new(BGP_NOMC_CEASE, BGP_NOMS_UNSPECIFIC, 0)) ;
+ return ;
+ }
+
+ bgp_session_route_refresh_recv(connection, rr) ;
+ return ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Process ORF Type and following ORF Entries.
+ *
+ * Expects there to be at least one ORF entry -- that is, the length of the
+ * ORF Entries may not be 0.
+ *
+ * Returns: 0 => OK
+ * -1 => invalid or malformed
+ */
+static int
+bgp_msg_orf_recv(bgp_connection connection, bgp_route_refresh rr,
+ qafx_bit_t qb, sucker sr)
{
- bgp_notify notification;
- notification = bgp_notify_new(code, sub_code, datalen);
- bgp_notify_append_data(notification, data, datalen);
- bgp_fsm_raise_exception(connection, except, notification);
-}
+ sucker_t ssr ;
+ int left ;
+ uint8_t orf_type ;
+ bgp_size_t orf_len ;
+ int unknown ;
+ int form ;
+ int ret ;
+
+ /* Suck up the ORF type and the length of the entries that follow */
+ left = suck_left(sr) - BGP_ORF_MIN_L ;
+ if (left >= 0)
+ {
+ orf_type = suck_b(sr) ;
+ orf_len = suck_w(sr) ;
+ } ;
+
+ /* The length may not be zero and may not exceed what there is left */
+ if ((orf_len == 0) || (left < orf_len))
+ {
+ zlog_info ("%s ORF route refresh length error: %d when %d left"
+ " (AFI/SAFI %d/%d, type %d length %d)",
+ connection->host, orf_len, left,
+ rr->afi, rr->safi, orf_type, orf_len) ;
+ return -1 ;
+ } ;
+
+ if (BGP_DEBUG (normal, NORMAL))
+ zlog_debug ("%s rcvd ORF type %d length %d",
+ connection->host, orf_type, orf_len);
+
+ /* Sex the ORF type */
+ form = bgp_form_none ;
+ unknown = 1 ;
+ switch (orf_type)
+ {
+ case BGP_ORF_T_PREFIX:
+ if ((connection->orf_prefix & bgp_form_rfc) != 0)
+ {
+ form = bgp_form_rfc ;
+ unknown = (qb != 0) ;
+ } ;
+ break ;
+
+ case BGP_ORF_T_PREFIX_pre:
+ if ((connection->orf_prefix & bgp_form_pre) != 0)
+ {
+ orf_type = BGP_ORF_T_PREFIX ;
+ form = bgp_form_pre ;
+ unknown = (qb != 0) ;
+ } ;
+ break ;
+
+ default:
+ break ;
+ } ;
+
+ /* Suck up the ORF entries. NB: orf_len != 0 */
+ suck_push(sr, orf_len, &ssr) ;
+
+ if (unknown)
+ bgp_orf_add_unknown(rr, orf_type, orf_len, suck_step(sr, orf_len)) ;
+ else
+ {
+ do
+ {
+ flag_t remove_all = 0 ;
+ flag_t remove = 0 ;
+ flag_t deny = 0 ;
+ uint8_t common ;
+
+ common = suck_b(sr) ;
+ switch (common & BGP_ORF_EA_MASK)
+ {
+ case BGP_ORF_EA_ADD:
+ break ;
+ case BGP_ORF_EA_REMOVE:
+ remove = 1 ;
+ break ;
+ case BGP_ORF_EA_RM_ALL:
+ remove_all = 1 ;
+ break ;
+ default:
+ zlog_info ("%s ORF route refresh invalid common byte: %u"
+ " (AFI/SAFI %d/%d, type %d length %d)",
+ connection->host, common,
+ rr->afi, rr->safi, orf_type, orf_len) ;
+ return -1 ;
+ } ;
+
+ deny = ((common & BGP_ORF_EA_DENY) != 0) ;
+
+ ret = 0 ;
+ if (remove_all)
+ bgp_orf_add_remove_all(rr, orf_type, form) ;
+ else
+ {
+ bgp_orf_entry orfe ;
+ orfe = bgp_orf_add(rr, orf_type, form, remove, deny) ;
+
+ switch (orf_type)
+ {
+ case BGP_ORF_T_PREFIX:
+ ret = bgp_msg_orf_prefix_recv(&orfe->body.orf_prefix, qb,
+ sr) ;
+ break ;
+
+ default:
+ zabort("Lost track of ORF type") ;
+ break ;
+ } ;
+
+ if (ret < 0)
+ {
+ zlog_info ("%s ORF route refresh invalid Prefix ORF entry"
+ " (AFI/SAFI %d/%d, type %d length %d)",
+ connection->host,
+ rr->afi, rr->safi, orf_type, orf_len) ;
+ return -1 ;
+ } ;
+ } ;
+
+ } while (suck_left(sr) > 0) ;
+ } ;
+
+ suck_pop_exact(sr, &ssr) ;
+ return 0 ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Process ORF Prefix entry, from after the common byte.
+ *
+ * This is for entries which are *not* remove-all
+ *
+ * Returns: 0 => OK
+ * -1 => invalid or malformed
+ */
+static int
+bgp_msg_orf_prefix_recv(orf_prefix orfpe, qafx_bit_t qb, sucker sr)
+{
+ pAF_t paf ;
+ int left ;
+
+ assert(qb != 0) ;
+ paf = get_pAF(qafx_num(qb)) ;
+
+ /* Must have the minimum Prefix ORF entry, less the common byte, left */
+ left = suck_left(sr) - (BGP_ORF_E_P_MIN_L - BGP_ORF_E_COM_L) ;
+ if (left >= 0)
+ {
+ uint8_t plen ;
+ uint8_t blen ;
+
+ orfpe->seq = suck_l(sr) ;
+ orfpe->ge = suck_b(sr) ; /* aka min */
+ orfpe->le = suck_b(sr) ; /* aka max */
+ plen = suck_b(sr) ;
+
+ memset(&orfpe->p, 0, sizeof(struct prefix)) ;
+
+ blen = blen = (plen + 7) / 8 ;
+ if ((left -= blen) >= 0)
+ {
+ orfpe->p.family = paf ;
+ orfpe->p.prefixlen = plen ;
+ if (blen != 0)
+ {
+ if (blen <= prefix_blen(&orfpe->p))
+ memcpy(&orfpe->p.u.prefix, suck_step(sr, blen), blen) ;
+ else
+ left = -1 ;
+ } ;
+ } ;
+ } ;
+
+ return left ;
+} ;
+
+/*==============================================================================
+ * BGP CAPABILITY message -- Dynamic Capabilities
+ */
+static void bgp_msg_capability_receive(bgp_connection connection,
+ bgp_size_t body_size)
+{
+ return ;
+} ;
diff --git a/bgpd/bgp_msg_read.h b/bgpd/bgp_msg_read.h
index 100cd597..1556f24c 100644
--- a/bgpd/bgp_msg_read.h
+++ b/bgpd/bgp_msg_read.h
@@ -32,8 +32,7 @@ bgp_msg_get_mlen(uint8_t* p) ;
extern int
bgp_msg_check_header(bgp_connection connection);
-extern void
-bgp_msg_dispatch(bgp_connection connection);
+typedef void bgp_msg_handler(bgp_connection connection, bgp_size_t size) ;
extern bgp_notify
bgp_msg_noms_o_bad_id(bgp_notify notification, bgp_id_t id) ;
diff --git a/bgpd/bgp_msg_write.c b/bgpd/bgp_msg_write.c
index 87bd41be..c0769578 100644
--- a/bgpd/bgp_msg_write.c
+++ b/bgpd/bgp_msg_write.c
@@ -313,7 +313,7 @@ bgp_open_options(struct stream *s, bgp_open_state open_state)
/* Route refresh. */
- if (open_state->can_r_refresh & bgp_cap_form_old)
+ if (open_state->can_r_refresh & bgp_form_pre)
{
stream_putc (s, BGP_OPEN_OPT_CAP) ;
stream_putc (s, CAPABILITY_CODE_REFRESH_LEN + 2) ;
@@ -321,7 +321,7 @@ bgp_open_options(struct stream *s, bgp_open_state open_state)
stream_putc (s, CAPABILITY_CODE_REFRESH_LEN) ;
} ;
- if (open_state->can_r_refresh & bgp_cap_form_old)
+ if (open_state->can_r_refresh & bgp_form_pre)
{
stream_putc (s, BGP_OPEN_OPT_CAP) ;
stream_putc (s, CAPABILITY_CODE_REFRESH_LEN + 2) ;
@@ -361,11 +361,11 @@ bgp_open_options(struct stream *s, bgp_open_state open_state)
if (!have_ipv6 && (afi == iAFI_IP6))
continue ;
- if (open_state->can_orf_prefix & bgp_cap_form_old)
+ if (open_state->can_orf_prefix & bgp_form_pre)
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)
+ if (open_state->can_orf_prefix & bgp_form_rfc)
bgp_open_capability_orf(s, afi, safi, CAPABILITY_CODE_ORF,
ORF_TYPE_PREFIX, mode) ;
} ;
@@ -462,7 +462,7 @@ bgp_msg_orf_remove_all(struct stream* s, bgp_size_t left) ;
static int
bgp_msg_orf_prefix(struct stream* s, uint8_t common,
- bgp_orf_prefix_entry orf_prefix, bgp_size_t left) ;
+ orf_prefix orfpe, bgp_size_t left) ;
/*------------------------------------------------------------------------------
* Make Route-Refresh message(s) and dispatch.
@@ -489,8 +489,9 @@ bgp_msg_send_route_refresh(bgp_connection connection, bgp_route_refresh rr)
bgp_size_t msg_len ;
int ret ;
- msg_type = connection->route_refresh_pre ? BGP_MT_ROUTE_REFRESH_pre
- : BGP_MT_ROUTE_REFRESH ;
+ msg_type = (connection->route_refresh == bgp_form_pre)
+ ? BGP_MT_ROUTE_REFRESH_pre
+ : BGP_MT_ROUTE_REFRESH ;
done = (bgp_orf_get_count(rr) == 0) ;
do
@@ -608,7 +609,8 @@ bgp_msg_orf_part(struct stream* s, bgp_connection connection,
orf_type = entry->orf_type ;
orf_type_sent = entry->orf_type ;
- if ((orf_type == BGP_ORF_T_PREFIX) && connection->orf_prefix_pre)
+ if ((orf_type == BGP_ORF_T_PREFIX) &&
+ (connection->orf_prefix == bgp_form_pre))
orf_type_sent = BGP_ORF_T_PREFIX_pre ;
stream_putc(s, orf_type_sent) ; /* ORF entries type */
@@ -638,8 +640,8 @@ bgp_msg_orf_part(struct stream* s, bgp_connection connection,
switch (entry->orf_type)
{
case BGP_ORF_T_PREFIX:
- done = bgp_msg_orf_prefix(s, common,
- &entry->body.orf_prefix, left) ;
+ done = bgp_msg_orf_prefix(s, common, &entry->body.orf_prefix,
+ left) ;
break ;
default:
zabort("unknown ORF type") ;
@@ -735,19 +737,19 @@ bgp_msg_orf_remove_all(struct stream* s, bgp_size_t left)
*/
static int
bgp_msg_orf_prefix(struct stream* s, uint8_t common,
- bgp_orf_prefix_entry orf_prefix, bgp_size_t left)
+ orf_prefix orfpe, bgp_size_t left)
{
- bgp_size_t plen = (orf_prefix->pfx.prefixlen + 7) / 8 ;
+ bgp_size_t blen = (orfpe->p.prefixlen + 7) / 8 ;
- if (left < (BGP_ORF_E_P_MIN_L + plen))
+ if (left < (BGP_ORF_E_P_MIN_L + blen))
return 0 ;
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) ;
+ stream_putl(s, orfpe->seq) ;
+ stream_putc(s, orfpe->ge) ; /* aka min */
+ stream_putc(s, orfpe->le) ; /* aka max */
+ stream_putc(s, orfpe->p.prefixlen) ;
+ stream_write(s, &orfpe->p.u.prefix, blen) ;
return 1 ;
} ;
diff --git a/bgpd/bgp_notification.c b/bgpd/bgp_notification.c
index 50fe35a9..691622e8 100644
--- a/bgpd/bgp_notification.c
+++ b/bgpd/bgp_notification.c
@@ -79,6 +79,23 @@ bgp_notify_new(bgp_nom_code_t code, bgp_nom_subcode_t subcode,
} ;
/*------------------------------------------------------------------------------
+ * Allocate and initialise new notification, complete with data
+ *
+ * Can specify an expected amount of data.
+ */
+extern bgp_notify
+bgp_notify_new_with_data(bgp_nom_code_t code, bgp_nom_subcode_t subcode,
+ const void* data, bgp_size_t len)
+{
+ bgp_notify notification ;
+
+ notification = bgp_notify_new(code, subcode, len) ;
+ bgp_notify_append_data(notification, data, len) ;
+
+ return notification ;
+} ;
+
+/*------------------------------------------------------------------------------
* Free notification structure
*
* Does nothing if there is no structure.
diff --git a/bgpd/bgp_notification.h b/bgpd/bgp_notification.h
index 59887f91..191b2ac8 100644
--- a/bgpd/bgp_notification.h
+++ b/bgpd/bgp_notification.h
@@ -120,6 +120,9 @@ struct bgp_notify
extern bgp_notify
bgp_notify_new(bgp_nom_code_t code, bgp_nom_subcode_t subcode,
bgp_size_t size) ;
+extern bgp_notify
+bgp_notify_new_with_data(bgp_nom_code_t code, bgp_nom_subcode_t subcode,
+ const void* data, bgp_size_t len) ;
extern void
bgp_notify_free(bgp_notify notification) ;
diff --git a/bgpd/bgp_open_state.c b/bgpd/bgp_open_state.c
index 3be152cc..4eb328e7 100644
--- a/bgpd/bgp_open_state.c
+++ b/bgpd/bgp_open_state.c
@@ -64,13 +64,17 @@ bgp_open_state_init_new(bgp_open_state state)
extern bgp_open_state
bgp_open_state_free(bgp_open_state state)
{
- bgp_cap_unknown unknown ;
+ bgp_cap_unknown unknown ;
+ bgp_cap_afi_safi afi_safi ;
if (state != NULL)
{
while ((unknown = vector_ream_keep(&state->unknowns)) != NULL)
XFREE(MTYPE_TMP, unknown) ;
+ while ((afi_safi = vector_ream_keep(&state->afi_safi)) != NULL)
+ XFREE(MTYPE_TMP, afi_safi) ;
+
XFREE(MTYPE_BGP_OPEN_STATE, state) ;
} ;
@@ -151,8 +155,8 @@ bgp_peer_open_state_init_new(bgp_open_state state, bgp_peer peer)
/* Route refresh. */
state->can_r_refresh = (peer->cap & PEER_CAP_REFRESH_ADV)
- ? (bgp_cap_form_old | bgp_cap_form_new)
- : bgp_cap_form_none ;
+ ? (bgp_form_pre | bgp_form_rfc)
+ : bgp_form_none ;
/* ORF capability. */
for (afi = qAFI_min ; afi <= qAFI_max ; ++afi)
@@ -168,8 +172,8 @@ bgp_peer_open_state_init_new(bgp_open_state state, bgp_peer peer)
state->can_orf_prefix = (state->can_orf_prefix_send |
state->can_orf_prefix_recv)
- ? (bgp_cap_form_old | bgp_cap_form_new)
- : bgp_cap_form_none ;
+ ? (bgp_form_pre | bgp_form_rfc)
+ : bgp_form_none ;
/* Dynamic Capabilities TODO: check requirement */
state->can_dynamic = ( CHECK_FLAG(peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY)
@@ -239,6 +243,50 @@ bgp_open_state_unknown_cap(bgp_open_state state, unsigned index)
} ;
/*==============================================================================
+ * Generic afi/safi capabilities handling.
+ *
+ */
+
+/*------------------------------------------------------------------------------
+ * Add given afi/safi capability and its value to the given open_state.
+ */
+extern bgp_cap_afi_safi
+bgp_open_state_afi_safi_add(bgp_open_state state, iAFI_t afi, iSAFI_t safi,
+ flag_t known, uint8_t cap_code)
+{
+ bgp_cap_afi_safi afi_safi ;
+
+ afi_safi = XCALLOC(MTYPE_TMP, sizeof(struct bgp_cap_afi_safi)) ;
+
+ afi_safi->known_afi_safi = known ;
+ afi_safi->afi = afi ;
+ afi_safi->safi = safi ;
+ afi_safi->cap_code = cap_code ;
+
+ vector_push_item(&state->afi_safi, afi_safi) ;
+
+ return afi_safi ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Get count of number of afi/safi capabilities in given open_state.
+ */
+extern int
+bgp_open_state_afi_safi_count(bgp_open_state state)
+{
+ return vector_end(&state->afi_safi) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Get n'th afi_safi capability -- if exists.
+ */
+extern bgp_cap_afi_safi
+bgp_open_state_afi_safi_cap(bgp_open_state state, unsigned index)
+{
+ return vector_get_item(&state->afi_safi, index) ;
+} ;
+
+/*==============================================================================
*
*/
@@ -317,9 +365,9 @@ bgp_peer_open_state_receive(bgp_peer peer)
}
/* Route refresh. */
- if (open_recv->can_r_refresh & bgp_cap_form_old)
+ if (open_recv->can_r_refresh & bgp_form_pre)
SET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV);
- else if (open_recv->can_r_refresh & bgp_cap_form_new)
+ else if (open_recv->can_r_refresh & bgp_form_rfc)
SET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV);
/* ORF */
@@ -336,16 +384,16 @@ bgp_peer_open_state_receive(bgp_peer peer)
/* ORF prefix. */
if (open_recv->can_orf_prefix_send)
{
- if (open_recv->can_orf_prefix & bgp_cap_form_old)
+ if (open_recv->can_orf_prefix & bgp_form_pre)
SET_FLAG (peer->cap, PEER_CAP_ORF_PREFIX_SM_OLD_RCV);
- else if (open_recv->can_orf_prefix & bgp_cap_form_new)
+ else if (open_recv->can_orf_prefix & bgp_form_rfc)
SET_FLAG (peer->cap, PEER_CAP_ORF_PREFIX_SM_RCV);
}
if (open_recv->can_orf_prefix_recv)
{
- if (open_recv->can_orf_prefix & bgp_cap_form_old)
+ if (open_recv->can_orf_prefix & bgp_form_pre)
SET_FLAG (peer->cap, PEER_CAP_ORF_PREFIX_RM_OLD_RCV);
- else if (open_recv->can_orf_prefix & bgp_cap_form_new)
+ else if (open_recv->can_orf_prefix & bgp_form_rfc)
SET_FLAG (peer->cap, PEER_CAP_ORF_PREFIX_RM_RCV);
}
diff --git a/bgpd/bgp_open_state.h b/bgpd/bgp_open_state.h
index 413fc07d..0612bbff 100644
--- a/bgpd/bgp_open_state.h
+++ b/bgpd/bgp_open_state.h
@@ -33,21 +33,6 @@
#endif
/*==============================================================================
- * Some BGP Capabilities have old and new forms. Wish to control whether to
- * send both old and/or new forms, and to track what form(s) received the
- * capability in.
- */
-typedef enum bgp_cap_form bgp_cap_form_t ;
-
-enum bgp_cap_form
-{
- bgp_cap_form_none = 0,
- bgp_cap_form_old = 1,
- bgp_cap_form_new = 2,
- bgp_cap_form_both = 3 /* _old and _new are bits ! */
-} ;
-
-/*==============================================================================
* BGP Open State.
*
* This structure encapsulates all the information that may be sent/received
@@ -63,20 +48,44 @@ struct bgp_cap_unknown /* to capture unknown capability */
uint8_t value[] ;
} ;
+typedef struct bgp_cap_mp* bgp_cap_mp ;
+struct bgp_cap_mp
+{
+} ;
+
typedef struct bgp_cap_orf* bgp_cap_orf ;
struct bgp_cap_orf
{
- flag_t known_afi_safi ;
flag_t known_orf_type ;
- iAFI_t afi ;
- iSAFI_t safi ;
-
uint8_t type ;
flag_t send ;
flag_t recv ;
} ;
+typedef struct bgp_cap_gr* bgp_cap_gr ;
+struct bgp_cap_gr
+{
+ flag_t has_preserved ;
+} ;
+
+typedef struct bgp_cap_afi_safi* bgp_cap_afi_safi ;
+struct bgp_cap_afi_safi
+{
+ flag_t known_afi_safi ;
+
+ iAFI_t afi ;
+ iSAFI_t safi ;
+
+ uint8_t cap_code ; /* eg BGP_CAN_MP_EXT */
+ union
+ {
+ struct bgp_cap_mp mp ;
+ struct bgp_cap_orf orf ;
+ struct bgp_cap_gr gr ;
+ } caps ;
+} ;
+
struct bgp_open_state
{
as_t my_as ; /* generic ASN */
@@ -90,8 +99,8 @@ 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/both */
- bgp_cap_form_t can_orf_prefix ; /* none/old/new/both */
+ bgp_form_t can_r_refresh ; /* none/old/new/both */
+ bgp_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 */
@@ -106,6 +115,7 @@ struct bgp_open_state
int restart_time ; /* Restart Time in seconds */
struct vector unknowns ; /* list of bgp_cap_unknown */
+ struct vector afi_safi ; /* various afi/safi capabilities */
} ;
/*==============================================================================
@@ -133,6 +143,15 @@ 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_cap_afi_safi
+bgp_open_state_afi_safi_add(bgp_open_state state, iAFI_t afi, iSAFI_t safi,
+ flag_t known, uint8_t cap_code) ;
+extern int
+bgp_open_state_afi_safi_count(bgp_open_state state) ;
+
+extern bgp_cap_afi_safi
+bgp_open_state_afi_safi_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_route_refresh.c b/bgpd/bgp_route_refresh.c
index d50f977b..11448e67 100644
--- a/bgpd/bgp_route_refresh.c
+++ b/bgpd/bgp_route_refresh.c
@@ -81,6 +81,15 @@ bgp_route_refresh_free(bgp_route_refresh rr)
} ;
/*------------------------------------------------------------------------------
+ * Set the defer flag as required
+ */
+extern void
+bgp_route_refresh_set_orf_defer(bgp_route_refresh rr, flag_t defer)
+{
+ rr->defer = (defer != 0) ;
+} ;
+
+/*------------------------------------------------------------------------------
* Allocate new bgp_orf_entry -- for known or unknown type.
*
* Is for known type if unknown_size == 0 !
@@ -95,7 +104,8 @@ bgp_route_refresh_free(bgp_route_refresh rr)
* 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_new(bgp_route_refresh rr, uint8_t orf_type, bgp_form_t form,
+ size_t unknown_size)
{
bgp_orf_entry orfe ;
size_t e_size ;
@@ -117,6 +127,7 @@ bgp_orf_entry_new(bgp_route_refresh rr, uint8_t orf_type, size_t unknown_size)
orfe = XCALLOC(MTYPE_BGP_ORF_ENTRY, sizeof(struct bgp_orf_entry) + e_size) ;
orfe->orf_type = orf_type ;
+ orfe->form = form ;
orfe->unknown = (unknown_size != 0) ;
vector_push_item(&rr->entries, orfe) ;
@@ -141,15 +152,16 @@ bgp_orf_entry_new(bgp_route_refresh rr, uint8_t orf_type, size_t unknown_size)
*
* 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)
+extern bgp_orf_entry
+bgp_orf_add(bgp_route_refresh rr, uint8_t orf_type, bgp_form_t form,
+ flag_t remove, flag_t deny)
{
- bgp_orf_entry orfe = bgp_orf_entry_new(rr, orf_type, 0) ;
+ bgp_orf_entry orfe = bgp_orf_entry_new(rr, orf_type, form, 0) ;
orfe->remove = (remove != 0) ;
orfe->deny = (deny != 0) ;
- return &orfe->body ;
+ return orfe ;
} ;
/*------------------------------------------------------------------------------
@@ -162,9 +174,9 @@ bgp_orf_add(bgp_route_refresh rr, uint8_t orf_type, flag_t remove, flag_t deny)
* 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_add_remove_all(bgp_route_refresh rr, uint8_t orf_type, bgp_form_t form)
{
- bgp_orf_entry orfe = bgp_orf_entry_new(rr, orf_type, 0) ;
+ bgp_orf_entry orfe = bgp_orf_entry_new(rr, orf_type, form, 0) ;
orfe->remove_all = 1 ;
} ;
@@ -178,7 +190,7 @@ 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,
+ bgp_orf_entry orfe = bgp_orf_entry_new(rr, orf_type, bgp_form_none,
(length > 0) ? length : 1) ;
if (length != 0)
diff --git a/bgpd/bgp_route_refresh.h b/bgpd/bgp_route_refresh.h
index 8ac6059b..b6e5eaf5 100644
--- a/bgpd/bgp_route_refresh.h
+++ b/bgpd/bgp_route_refresh.h
@@ -26,25 +26,17 @@
#include "bgpd/bgp_common.h"
#include "lib/prefix.h"
+#include "lib/plist.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 orf_prefix* orf_prefix ; /* see lib/plist.h */
typedef struct bgp_orf_unknown_entry* bgp_orf_unknown_entry ;
struct bgp_orf_unknown_entry
@@ -56,7 +48,8 @@ struct bgp_orf_unknown_entry
typedef struct bgp_orf_entry* bgp_orf_entry ;
struct bgp_orf_entry
{
- uint8_t orf_type ; /* BGP_ORF_T_xxx */
+ uint8_t orf_type ; /* BGP_ORF_T_xxx -- _rfc version ! */
+ bgp_form_t form ; /* bgp_form_none/_rfc/_pre */
flag_t unknown ; /* ignore everything other than the */
/* unknown data part */
@@ -67,7 +60,7 @@ struct bgp_orf_entry
flag_t deny ; /* otherwise: permit */
union { /* must be last... */
- struct bgp_orf_prefix_entry orf_prefix ;
+ struct orf_prefix orf_prefix ;
struct bgp_orf_unknown_entry orf_unknown ; /*... flexible array. */
} body ;
} ;
@@ -105,16 +98,17 @@ 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) ;
+bgp_route_refresh_free(bgp_route_refresh rr) ;
extern void
-bgp_route_refresh_free(bgp_route_refresh rr) ;
+bgp_route_refresh_set_orf_defer(bgp_route_refresh rr, flag_t defer) ;
-extern void*
-bgp_orf_add(bgp_route_refresh rr, uint8_t orf_type, flag_t remove, flag_t deny);
+extern bgp_orf_entry
+bgp_orf_add(bgp_route_refresh rr, uint8_t orf_type, bgp_form_t form,
+ flag_t remove, flag_t deny) ;
extern void
-bgp_orf_add_remove_all(bgp_route_refresh rr, uint8_t orf_type) ;
+bgp_orf_add_remove_all(bgp_route_refresh rr, uint8_t orf_type, bgp_form_t form);
extern void
bgp_orf_add_unknown(bgp_route_refresh rr, uint8_t orf_type, bgp_size_t length,
diff --git a/lib/qafi_safi.h b/lib/qafi_safi.h
index 40915ca5..610bf0b8 100644
--- a/lib/qafi_safi.h
+++ b/lib/qafi_safi.h
@@ -139,6 +139,11 @@ typedef struct qAFI_SAFI qAFI_SAFI_t ;
typedef struct qAFI_SAFI* qAFI_SAFI ;
/*==============================================================================
+ * POSIX address family type
+ */
+typedef int pAF_t ;
+
+/*==============================================================================
* Quagga AFI/SAFI values -- original macro definitions
*/