diff options
-rw-r--r-- | bgpd/bgp.h | 6 | ||||
-rw-r--r-- | bgpd/bgp_common.c | 12 | ||||
-rw-r--r-- | bgpd/bgp_common.h | 53 | ||||
-rw-r--r-- | bgpd/bgp_connection.c | 18 | ||||
-rw-r--r-- | bgpd/bgp_connection.h | 8 | ||||
-rw-r--r-- | bgpd/bgp_fsm.c | 34 | ||||
-rw-r--r-- | bgpd/bgp_fsm.h | 3 | ||||
-rw-r--r-- | bgpd/bgp_msg_read.c | 717 | ||||
-rw-r--r-- | bgpd/bgp_msg_read.h | 3 | ||||
-rw-r--r-- | bgpd/bgp_msg_write.c | 38 | ||||
-rw-r--r-- | bgpd/bgp_notification.c | 17 | ||||
-rw-r--r-- | bgpd/bgp_notification.h | 3 | ||||
-rw-r--r-- | bgpd/bgp_open_state.c | 70 | ||||
-rw-r--r-- | bgpd/bgp_open_state.h | 61 | ||||
-rw-r--r-- | bgpd/bgp_route_refresh.c | 28 | ||||
-rw-r--r-- | bgpd/bgp_route_refresh.h | 28 | ||||
-rw-r--r-- | lib/qafi_safi.h | 5 |
17 files changed, 833 insertions, 271 deletions
@@ -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*)¬ify_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*)¬ify_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 */ |