diff options
-rw-r--r-- | bgpd/bgp.h | 120 | ||||
-rw-r--r-- | bgpd/bgp_common.c | 50 | ||||
-rw-r--r-- | bgpd/bgp_common.h | 126 | ||||
-rw-r--r-- | bgpd/bgp_connection.c | 16 | ||||
-rw-r--r-- | bgpd/bgp_connection.h | 6 | ||||
-rw-r--r-- | bgpd/bgp_fsm.c | 3 | ||||
-rw-r--r-- | bgpd/bgp_msg_read.c | 1707 | ||||
-rw-r--r-- | bgpd/bgp_msg_read.h | 4 | ||||
-rw-r--r-- | bgpd/bgp_msg_write.c | 10 | ||||
-rw-r--r-- | bgpd/bgp_notification.c | 102 | ||||
-rw-r--r-- | bgpd/bgp_notification.h | 12 | ||||
-rw-r--r-- | bgpd/bgp_open.h | 11 | ||||
-rw-r--r-- | bgpd/bgp_open_state.c | 73 | ||||
-rw-r--r-- | bgpd/bgp_open_state.h | 24 | ||||
-rw-r--r-- | bgpd/bgp_packet.c | 2 | ||||
-rw-r--r-- | bgpd/bgp_session.h | 16 | ||||
-rw-r--r-- | lib/distribute.c | 66 | ||||
-rw-r--r-- | lib/if_rmap.c | 54 | ||||
-rw-r--r-- | lib/qafi_safi.h | 21 | ||||
-rw-r--r-- | lib/stream.c | 7 | ||||
-rw-r--r-- | lib/stream.h | 1 |
21 files changed, 1532 insertions, 899 deletions
@@ -164,8 +164,9 @@ typedef U16 BGP_MH_LEN_T ; /* length of message inc. header: octets */ typedef U8 BGP_MH_TYPE_T ; /* BGP message type */ typedef UBX BGP_MH_BODY_T ; /* rest is body of message */ +VALUE(BGP_MH_MARKER_L = sizeof(BGP_MH_MARKER_T)) ; VALUE(BGP_MH_HEAD_L = /* message header length */ - sizeof(BGP_MH_MARKER_T) + BGP_MH_MARKER_L + sizeof(BGP_MH_LEN_T) + sizeof(BGP_MH_TYPE_T) ) ; CONFIRM(BGP_MH_HEAD_L == 19) ; /* well known value ! */ @@ -192,7 +193,9 @@ enum BGP_MT BGP_MT_KEEPALIVE = 4, BGP_MT_ROUTE_REFRESH = 5, /* RFC2918 */ - BGP_MT_MAX = 5, /* max known message type */ + BGP_MT_CAPABILITY = 6, /* draft-ietf-idr-dynamic-cap-10 */ + + BGP_MT_MAX = 6, /* max known message type */ BGP_MT_ROUTE_REFRESH_pre = 128 /* pre RFC2918 (Sep-2000) */ } ; @@ -264,6 +267,9 @@ typedef UBX BGP_CAP_VALUE_T ; /* variable -- depending on code */ VALUE(BGP_CAP_MIN_L = sizeof(BGP_CAP_CODE_T) + sizeof(BGP_CAP_LEN_T)) ; /* min len of a capability announcement */ +VALUE(BGP_CAP_MAX_L = 255) ; /* max len of a capability announcement */ +CONFIRM(sizeof(BGP_CAP_LEN_T) == 1) ; + enum /* order */ { BGP_CAP_CODE, @@ -284,7 +290,8 @@ enum BGP_CAN { BGP_CAN_G_RESTART = 64, /* Graceful Restart RFC4724 */ BGP_CAN_AS4 = 65, /* Supports 4-octet AS number RFC4893 */ - /* 66, Deprecated 6-Apr-2003 */ + BGP_CAN_DYNAMIC_CAP_old = 66, /* Dynamic Capability (draft 02) [Chen] + Deprecated 6-Apr-2003 */ BGP_CAN_DYNAMIC_CAP= 67, /* Dynamic Capability [Chen] */ BGP_CAN_MULTI_SESS = 68, /* Multisession Capability [Appanna] */ BGP_CAN_ADD_PATH = 69, /* ADD-PATH [draft-idr] */ @@ -437,6 +444,9 @@ enum BGP_NOMC BGP_NOMC_FSM = 5, /* Finite State Machine Error */ BGP_NOMC_CEASE = 6, /* Cease RFC4486 */ + BGP_NOMC_DYN_CAP = 7, /* Dynamic Capability + draft-ietf-idr-dynamic-cap-10.txt */ + BGP_NOMC_MAX = 6 /* max known error code */ } ; @@ -526,6 +536,17 @@ enum BGP_NOMS_CEASE /* BGP_NOMC_CEASE subcodes RFC4486 */ BGP_NOMS_C_MAX = 8 /* max known subcode */ } ; +enum BGP_DYN_CAP /* BGP_NOMC_DYN_CAP subcodes + draft-ietf-idr-dynamic-cap-10.txt */ +{ + BGP_NOMS_D_UNKN_SEQ = 1, /* Unknown Sequence Number MUST */ + BGP_NOMS_D_INV_LEN = 2, /* Invalid Capability Length MUST */ + BGP_NOMS_D_MALFORM = 3, /* Malformed Capability Length MUST */ + BGP_NOMS_D_UNSUP = 4, /* Unsupported Capability MUST */ + + BGP_NOMS_D_MAX = 4 /* max known subcode */ +} ; + /* Keepalive Message (type = BGP_MT_KEEPALIVE) -------------------------------*/ VALUE(BGP_KAM_L = BGP_MH_HEAD_L) ; /* Keepalive message is entirely empty */ @@ -539,11 +560,11 @@ typedef U16 BGP_RRM_AFI_T ; /* Address Family Identifier */ typedef U8 BGP_RRM_RES_T ; /* reserved = 0 */ typedef U8 BGP_RRM_SAFI_T ; /* Subsequent Address Family Identifier */ -VALUE(BGP_RRM_L = BGP_MH_HEAD_L /* Route Refresh length */ - + sizeof(BGP_RRM_AFI_T) - + sizeof(BGP_RRM_RES_T) - + sizeof(BGP_RRM_SAFI_T) ) ; -CONFIRM(BGP_RRM_L == 23) ; /* well known value ! */ +VALUE(BGP_RRM_MIN_L = BGP_MH_HEAD_L /* Route Refresh length */ + + sizeof(BGP_RRM_AFI_T) + + sizeof(BGP_RRM_RES_T) + + sizeof(BGP_RRM_SAFI_T) ) ; +CONFIRM(BGP_RRM_MIN_L == 23) ; /* well known value ! */ typedef U8 BGP_RRM_ORF_WHEN_T ; /* when to refresh -- see RFC5291 */ typedef UBX BGP_RRM_ORFS_T ; /* variable... see below */ @@ -625,6 +646,12 @@ VALUE(BGP_ORF_E_P_MIN_L = BGP_ORF_E_COM_L + sizeof(BGP_ORF_E_P_MAX_T) + sizeof(BGP_ORF_E_P_LEN_T) ) ; +/* Dynamic Capability Message (type = BGP_MT_CAPABILITY) ----------------------- + * + * If it's just header + 4 bytes, it's an RFC2918 Route Refresh request. + * If it's longer that that, it's an RFC5291 ORF + */ + /*============================================================================== * Capability Values */ @@ -645,47 +672,59 @@ VALUE(BGP_CAP_MPE_L = 4) ; /* Fixed length == 4 ! */ VALUE(BGP_CAP_RRF_L = 0) ; /* no value part */ -/* Outbound Route Filtering -- BGP_CAN_ORF -- RFC5291 ------------------------*/ - -typedef U16 BGP_CAP_ORF_AFI_T ; /* Address Family Identifier */ -typedef U8 BGP_CAP_ORF_RES_T ; /* Reserved: 0 */ -typedef U8 BGP_CAP_ORF_SAFI_T ; /* Subsequent Address Family */ -typedef U8 BGP_CAP_ORF_COUNT_T ; /* number of ORF Types supported */ -typedef UBX BGP_CAP_ORF_CAN_T ; /* variable -- 2 byte entries as below */ - -VALUE(BGP_CAP_ORF_MIN_L = sizeof(BGP_CAP_ORF_AFI_T) - + sizeof(BGP_CAP_ORF_RES_T) - + sizeof(BGP_CAP_ORF_SAFI_T) - + sizeof(BGP_CAP_ORF_COUNT_T) ) ; +/* Outbound Route Filtering -- BGP_CAN_ORF -- RFC5291 -------------------------- + * + * The capability value is *one* or more of the following entries: + */ +typedef U16 BGP_CAP_ORFE_AFI_T ; /* Address Family Identifier */ +typedef U8 BGP_CAP_ORFE_RES_T ; /* Reserved: 0 */ +typedef U8 BGP_CAP_ORFE_SAFI_T ; /* Subsequent Address Family */ +typedef U8 BGP_CAP_ORFE_COUNT_T ; /* number of ORF Types supported */ +typedef UBX BGP_CAP_ORFE_TYPES_T ; /* variable -- 2 byte entries as below */ -VALUE(BGP_CAP_ORF_COUNT_O = sizeof(BGP_CAP_ORF_AFI_T) - + sizeof(BGP_CAP_ORF_RES_T) - + sizeof(BGP_CAP_ORF_SAFI_T) ) ; +VALUE(BGP_CAP_ORFE_MIN_L = sizeof(BGP_CAP_ORFE_AFI_T) + + sizeof(BGP_CAP_ORFE_RES_T) + + sizeof(BGP_CAP_ORFE_SAFI_T) + + sizeof(BGP_CAP_ORFE_COUNT_T) ) ; enum /* order */ { - BGP_CAP_ORF_AFI, - BGP_CAP_ORF_RES, - BGP_CAP_ORF_SAFI, - BGP_CAP_ORF_COUNT, - BGP_CAP_ORF_CAN + BGP_CAP_ORFE_AFI, + BGP_CAP_ORFE_RES, + BGP_CAP_ORFE_SAFI, + BGP_CAP_ORFE_COUNT, + BGP_CAP_ORFE_TYPES } ; -/* Entries saying what ORF Types can be supported and how.....................*/ - -typedef U8 BGP_CAP_ORFE_TYPE_T ; /* the ORF Type supported */ -typedef U8 BGP_CAP_ORFE_CAN_T ; /* what can do with ORF Type */ +/* Entries saying what ORF Types can be supported and how....................... + * + * There are BGP_CAP_ORF_COUNT of these. + */ +typedef U8 BGP_CAP_ORFT_TYPE_T ; /* the ORF Type supported */ +typedef U8 BGP_CAP_ORFT_MODE_T ; /* what can do with ORF Type */ -VALUE(BGP_CAP_ORFE_L = sizeof(BGP_CAP_ORFE_TYPE_T) - + sizeof(BGP_CAP_ORFE_CAN_T)) ; +VALUE(BGP_CAP_ORFT_L = sizeof(BGP_CAP_ORFT_TYPE_T) + + sizeof(BGP_CAP_ORFT_MODE_T)) ; /* length of ORF capability Type entry */ +enum /* order */ +{ + BGP_CAP_ORFT_TYPE, + BGP_CAP_ORFT_MODE, +} ; -/* Values for the BGP_CAP_ORFE_CAN field */ +/* Values for the BGP_CAP_ORFT_TYPE field */ +enum +{ + BGP_CAP_ORFT_T_PFIX = 64, /* Address Prefix ORF */ + BGP_CAP_ORFT_T_PFIX_pre = 128, /* Address Prefix ORF, pre-RFC */ +} ; +/* Values for the BGP_CAP_ORFT_MODE field */ enum { - BGP_CAP_ORFE_CAN_RECV = 1, /* willing to receive ) can be... */ - BGP_CAP_ORFE_CAN_SEND = 2 /* would like to send ) ... combined */ + BGP_CAP_ORFT_M_RECV = 1, /* willing to receive */ + BGP_CAP_ORFT_M_SEND = 2, /* would like to send */ + BGP_CAP_ORFT_M_BOTH = 3 /* may be combined */ } ; /* Multiple Routes to a Destination (Labels) -- BGP_CAN_M_ROUTES -- RFC3107 ---- @@ -734,6 +773,11 @@ typedef U32 BGP_CAP_AS4_MY_AS_T ; /* can do AS4, and this is me AS4-wise */ VALUE(BGP_CAP_AS4_L = sizeof(BGP_CAP_AS4_MY_AS_T)) ; +/* Dynamic Capability -- BGP_CAN_DYNAMIC_CAP -- draft-10----------------------*/ +/* draft-ietf-idr-dynamic-cap-10 15-Jan-2010 */ + +VALUE(BGP_CAP_DYN_L = 0) ; + /*============================================================================== * Attributes -- form of the Path Attributes in an UPDATE Message * @@ -823,6 +867,8 @@ enum BGP_ASN { BGP_ASN_RES2 = 65535, /* Start of Reservation 2 (0xFFFF) */ + BGP_AS2_MAX = 65535, /* Last of the Mohicans (0xFFFF) */ + BGP_AS4_DOC_S = AS4(1,0), /* Start of Docm. & Samples AS4 (65536) */ BGP_AS4_DOC_E = AS4(1,15), /* End (65531) */ diff --git a/bgpd/bgp_common.c b/bgpd/bgp_common.c index 15ecdf3b..90281ff5 100644 --- a/bgpd/bgp_common.c +++ b/bgpd/bgp_common.c @@ -109,11 +109,12 @@ const iSAFI_t iSAFI_map[] = } ; /*============================================================================== - * Convert iAFI/iSAFI => qafx_num_t - * and qAFI/qSAFI => qafx_num_t + * Convert iAFI/iSAFI => qafx_num_t -- tolerates unknown/reserved + * and qAFI/qSAFI => qafx_num_t -- tolerates undef, but not unknown */ -/* iAFI/iSAFI = qafx_num_t unknowns => qafx_num_other +/*------------------------------------------------------------------------------ + * iAFI/iSAFI => qafx_num_t unknowns => qafx_num_other * reserved => qafx_num_undef */ extern qafx_num_t @@ -170,7 +171,8 @@ qafx_num_from_iAFI_iSAFI(iAFI_t afi, iSAFI_t safi) return qafx_num_other ; } ; -/* qAFI/qSAFI = qafx_num_t +/*------------------------------------------------------------------------------ + * qAFI/qSAFI => qafx_num_t * * NB: qAFI_undef with any qSAFI_xxx => qafx_num_undef * qSAFI_undef with any qAFI_xxx => qafx_num_undef @@ -228,3 +230,43 @@ qafx_num_from_qAFI_qSAFI(qAFI_t afi, qSAFI_t safi) zabort("invalid qAFI or qSAFI") ; } ; + +/*============================================================================== + * Convert iAFI/iSAFI => qafx_bit_t -- tolerates unknown/reserved + * and qAFI/qSAFI => qafx_bit_t -- tolerates undef, but not unknown + */ + +/*------------------------------------------------------------------------------ + * iAFI/iSAFI => qafx_bit_t unknowns => 0 + * reserved => 0 + */ +extern qafx_bit_t +qafx_bit_from_iAFI_iSAFI(iAFI_t afi, iSAFI_t safi) +{ + qafx_num_t qn = qafx_num_from_iAFI_iSAFI(afi, safi) ; + + if ((qn != qafx_num_undef) && (qn != qafx_num_other)) + return qafx_bit(qn) ; + else + return 0 ; +} ; + +/*------------------------------------------------------------------------------ + * qAFI/qSAFI => qafx_bit_t + * + * NB: qAFI_undef with any qSAFI_xxx => 0 + * qSAFI_undef with any qAFI_xxx => 0 + * qSAFI_Unused qith any qAFI_xxx => 0 + * + * NB: any unrecognised qAFI/qSAFI combinations => FATAL error + */ +extern qafx_bit_t +qafx_bit_from_qAFI_qSAFI(qAFI_t afi, qSAFI_t safi) +{ + qafx_num_t qn = qafx_num_from_qAFI_qSAFI(afi, safi) ; + + if ((qn != qafx_num_undef) && (qn != qafx_num_other)) + return qafx_bit(qn) ; + else + return 0 ; +} ; diff --git a/bgpd/bgp_common.h b/bgpd/bgp_common.h index 221b255a..a2722ed1 100644 --- a/bgpd/bgp_common.h +++ b/bgpd/bgp_common.h @@ -25,7 +25,7 @@ #include <stdint.h> #include "bgpd/bgp.h" #include "qafi_safi.h" -#include "confirm.h" +#include "lib/zassert.h" #ifndef Inline #define Inline static inline @@ -282,8 +282,11 @@ get_iSAFI(qafx_num_t num) } ; /*============================================================================== - * Conversions for qAFI/qSAFI => qafx_num_t - * and iAFI/iSAFI => qafx_num_t + * Conversions for iAFI/iSAFI => qafx_num_t + * and qAFI/qSAFI => qafx_num_t + * + * and iAFI/iSAFI => qafx_bit_t + * and qAFI/qSAFI => qafx_bit_t */ extern qafx_num_t @@ -292,5 +295,122 @@ qafx_num_from_iAFI_iSAFI(iAFI_t afi, iSAFI_t safi) ; extern qafx_num_t qafx_num_from_qAFI_qSAFI(qAFI_t afi, qSAFI_t safi) ; +extern qafx_bit_t +qafx_bit_from_iAFI_iSAFI(iAFI_t afi, iSAFI_t safi) ; + +extern qafx_bit_t +qafx_bit_from_qAFI_qSAFI(qAFI_t afi, qSAFI_t safi) ; + +/*============================================================================== + * Buffer sucking + * + * + */ + +typedef uint8_t* ptr_t ; + +typedef struct sucker sucker_t ; +typedef struct sucker* sucker ; +struct sucker +{ + ptr_t start ; /* current known start */ + ptr_t ptr ; /* current read pointer */ + ptr_t end ; /* current known end */ +} ; + +Inline void +suck_init(sucker sr, void* start, unsigned length) +{ + sr->start = (ptr_t)start ; + sr->ptr = (ptr_t)start ; + sr->end = (ptr_t)start + length ; +} + +Inline int +suck_left(sucker sr) +{ + return sr->end - sr->ptr ; +} ; + +Inline int +suck_total(sucker sr) +{ + return sr->end - sr->start ; +} ; + +Inline ptr_t +suck_start(sucker sr) +{ + return sr->start ; +} ; + +Inline void +suck_push(sucker sr, unsigned length, sucker sv) +{ + *sv = *sr ; + sr->start = sr->ptr ; + sr->end = sr->ptr + length ; + dassert(sr->end <= sv->end) ; +} ; + +Inline void +suck_pop(sucker sr, sucker sv) +{ + dassert((sr->ptr <= sr->end) && (sr->end <= sv->end)) ; + sr->start = sv->start ; + sr->ptr = sr->end ; + sr->end = sv->end ; +} ; + +Inline void +suck_pop_exact(sucker sr, sucker sv) +{ + dassert(sr->ptr == sr->end) ; + sr->start = sv->start ; + sr->end = sv->end ; +} ; + +Inline void +suck_x(sucker sr) +{ + ++sr->ptr ; + dassert(sr->ptr <= sr->end) ; +} ; + +Inline void +suck_nx(sucker sr, unsigned n) +{ + sr->ptr += n ; + dassert(sr->ptr <= sr->end) ; +} ; + +Inline uint8_t +suck_b(sucker sr) +{ + dassert(sr->ptr < sr->end) ; + return *sr->ptr++ ; +} ; + +Inline uint16_t +suck_w(sucker sr) +{ + uint16_t w ; + dassert((sr->ptr + 1) < sr->end) ; + w = *sr->ptr++ ; + return (w << 8) + *sr->ptr++ ; +} ; + +Inline uint32_t +suck_l(sucker sr) +{ + uint32_t l ; + dassert((sr->ptr + 3) < sr->end) ; + l = *sr->ptr++ ; + l = (l << 8) + *sr->ptr++ ; + l = (l << 8) + *sr->ptr++ ; + return (l << 8) + *sr->ptr++ ; +} ; + + #endif /* _QUAGGA_BGP_COMMON_H */ diff --git a/bgpd/bgp_connection.c b/bgpd/bgp_connection.c index 8ceb9db6..2e10eaf1 100644 --- a/bgpd/bgp_connection.c +++ b/bgpd/bgp_connection.c @@ -126,8 +126,11 @@ bgp_connection_init_new(bgp_connection connection, bgp_session session, * * keepalive_timer_interval none -- set when connection is opened * * as4 not AS4 conversation * * route_refresh_pre not pre-RFC ROUTE-REFRESH + * * orf_prefix_pre not pre-RFC ORF by prefix * * read_pending nothing pending * * read_header not reading header + * * msg_type none -- set when reading message + * * msg_size none -- set when reading message * * notification_pending nothing pending * * wbuff all pointers NULL -- empty buffer */ @@ -232,8 +235,7 @@ bgp_connection_make_primary(bgp_connection connection) * Copy the negotiated hold_timer_interval and keepalive_timer_interval * Copy the su_local and su_remote */ - session->open_recv = connection->open_recv ; - connection->open_recv = NULL ; /* no longer interested in this */ + bgp_open_state_set_mov(&session->open_recv, &connection->open_recv) ; XFREE(MTYPE_BGP_PEER_HOST, connection->host) ; bgp_connection_init_host(connection, "") ; @@ -243,6 +245,7 @@ bgp_connection_make_primary(bgp_connection connection) session->as4 = connection->as4 ; session->route_refresh_pre = connection->route_refresh_pre ; + session->orf_prefix_pre = connection->orf_prefix_pre ; sockunion_set_mov(&session->su_local, &connection->su_local) ; sockunion_set_mov(&session->su_remote, &connection->su_remote) ; @@ -895,9 +898,9 @@ bgp_connection_read_action(qps_file qf, void* file_info) * * Exits loop iff completes a BGP message. */ - while (1) + while (want > 0) { - ret = stream_read_unblock(connection->ibuf, qps_file_fd(&connection->qf), + ret = stream_read_nonblock(connection->ibuf, qps_file_fd(&connection->qf), want) ; if (ret >= 0) { @@ -915,8 +918,6 @@ bgp_connection_read_action(qps_file qf, void* file_info) want = bgp_msg_check_header(connection) ; /* returns balance of message */ - if (want < 0) - return ; /* failed in header check */ } else { @@ -925,6 +926,9 @@ 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) ; diff --git a/bgpd/bgp_connection.h b/bgpd/bgp_connection.h index 2bffc5be..5ce623cd 100644 --- a/bgpd/bgp_connection.h +++ b/bgpd/bgp_connection.h @@ -151,13 +151,17 @@ struct bgp_connection flag_t as4 ; /* subject to negotiation */ flag_t route_refresh_pre ; /* subject to negotiation */ + flag_t orf_prefix_pre ; /* subject to negotiation */ struct qtimer hold_timer ; struct qtimer keepalive_timer ; struct stream* ibuf ; /* a single input "stream" */ unsigned read_pending ; /* how much input waiting for */ - int read_header ; /* reading message header */ + + flag_t read_header ; /* reading message header */ + uint8_t msg_type ; /* copy of message type */ + bgp_size_t msg_size ; /* size of message *body* */ struct stream* obuf ; /* a single output "stream" */ diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index d26e7e6e..cb899797 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -1924,7 +1924,8 @@ static bgp_fsm_action(bgp_fsm_recv_open) bgp_connection loser ; /* NB: bgp_id in open_state is in *host* order */ - loser = (session->open_send->bgp_id < sibling->open_recv->bgp_id) + loser = (ntohl(session->open_send->bgp_id) < + ntohl(sibling->open_recv->bgp_id)) ? connection : sibling ; diff --git a/bgpd/bgp_msg_read.c b/bgpd/bgp_msg_read.c index bbe8796d..58a80485 100644 --- a/bgpd/bgp_msg_read.c +++ b/bgpd/bgp_msg_read.c @@ -35,26 +35,7 @@ /* prototypes */ -static int bgp_msg_marker_all_one (struct stream *s, int length); static int bgp_msg_open_receive (bgp_connection connection, bgp_size_t size); -static as_t bgp_msg_peek_for_as4_capability (bgp_connection connection, - u_char length); -static as_t bgp_msg_capability_as4 (bgp_connection connection, - struct capability_header *hdr); -static int bgp_msg_open_option_parse (bgp_connection connection, u_char length, - int *capability); -static int bgp_msg_capability_parse (bgp_connection connection, size_t length, - u_char **error); -static int bgp_msg_capability_mp (bgp_connection connection, - struct capability_header *hdr); -static int bgp_msg_capability_restart (bgp_connection connection, - struct capability_header *caphdr); -static int bgp_msg_capability_orf_entry (bgp_connection connection, - struct capability_header *hdr); -static int bgp_msg_capability_orf (bgp_connection connection, - struct capability_header *hdr); -static void bgp_msg_capability_orf_not_support (char *host, afi_t afi, - safi_t safi, u_char type, u_char mode); 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); @@ -70,138 +51,169 @@ static void bgp_msg_notify_send_with_data (bgp_connection connection, extern bgp_size_t bgp_msg_get_mlen(uint8_t* p) { - return (*(p + BGP_MARKER_SIZE)) + (*(p + BGP_MARKER_SIZE + 1) << 8) ; + return (*(p + BGP_MH_MARKER_L)) + (*(p + BGP_MH_MARKER_L + 1) << 8) ; } ; -/* read and validate header. - * return >= 0 number of bytes still to read + +/*------------------------------------------------------------------------------ + * Header validation support. + */ + /* 0 1 2 3 */ +static const uint8_t bgp_header[] = { 0xFF, 0xFF, 0xFF, 0xFF, /* 4 */ + 0xFF, 0xFF, 0xFF, 0xFF, /* 8 */ + 0xFF, 0xFF, 0xFF, 0xFF, /* 12 */ + 0xFF, 0xFF, 0xFF, 0xFF /* 16 */ + } ; +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] = +{ + [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 +} ; + +/*------------------------------------------------------------------------------ + * The message size field is invalid per RFC + * + * Issue notification and kick FSM. + */ +static int +bgp_msg_header_bad_len(bgp_connection connection, uint8_t type, bgp_size_t size) +{ + uint16_t notify_size = htons(size) ; + + if (BGP_DEBUG (normal, NORMAL)) + plog_debug (connection->log, + "%s bad message length - %d for %s", + connection->host, size, + type == 128 ? "ROUTE-REFRESH" : bgp_type_str[(int) 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 ; +} ; + +/*------------------------------------------------------------------------------ + * Validate header part of BGP message. + * + * Have just read the header part (BGP_MH_HEAD_L) into connection->ibuf, need + * to check it's valid, and find how much more to read to complete the + * message. + * + * Advances the stream getp past the header. + * + * Plants: msg_type -- the message type + * msg_size -- the size of the message body + * + * in the connection, ready for bgp_msg_dispatch(). + * + * return >= 0 number of bytes still to read (ie msg_size) * return -1 error */ int bgp_msg_check_header(bgp_connection connection) { - u_char type = 0; - bgp_size_t size; - char notify_data_length[2]; - bgp_session session = connection->session; + uint8_t type ; + bgp_size_t size ; + bgp_size_t min_size ; - assert(session); - - /* Get size and type. */ - stream_forward_getp (connection->ibuf, BGP_MARKER_SIZE); - memcpy (notify_data_length, stream_pnt (connection->ibuf), 2); + /* Get size and type. */ + stream_forward_getp (connection->ibuf, BGP_MH_MARKER_L); size = stream_getw (connection->ibuf); type = stream_getc (connection->ibuf); if (BGP_DEBUG (normal, NORMAL) && type != 2 && type != 0) zlog_debug ("%s rcv message type %d, length (excl. header) %d", - session->host, type, size - BGP_HEADER_SIZE); + connection->host, type, size - BGP_MH_HEAD_L); - /* Marker check */ - if (((type == BGP_MSG_OPEN) || (type == BGP_MSG_KEEPALIVE)) - && ! bgp_msg_marker_all_one (connection->ibuf, BGP_MARKER_SIZE)) + /* 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) { bgp_msg_notify_send (connection, bgp_session_eInvalid_msg, BGP_NOTIFY_HEADER_ERR, BGP_NOTIFY_HEADER_NOT_SYNC); return -1; - } + } ; + + /* BGP type check. */ + min_size = bgp_type_min_size[type] ; - /* BGP type check. */ - if (type != BGP_MSG_OPEN && type != BGP_MSG_UPDATE - && type != BGP_MSG_NOTIFY && type != BGP_MSG_KEEPALIVE - && type != BGP_MSG_ROUTE_REFRESH_NEW - && type != BGP_MSG_ROUTE_REFRESH_OLD - && type != BGP_MSG_CAPABILITY) + if (min_size == 0) { if (BGP_DEBUG (normal, NORMAL)) - plog_debug (session->log, + plog_debug (connection->log, "%s unknown message type 0x%02x", - session->host, type); - bgp_msg_notify_send_with_data (connection, bgp_session_eInvalid_msg, - BGP_NOTIFY_HEADER_ERR, - BGP_NOTIFY_HEADER_BAD_MESTYPE, - &type, 1); - return -1; - } + connection->host, type); - /* Mimimum packet length check. */ - if ((size < BGP_HEADER_SIZE) - || (size > BGP_MAX_PACKET_SIZE) - || (type == BGP_MSG_OPEN && size < BGP_MSG_OPEN_MIN_SIZE) - || (type == BGP_MSG_UPDATE && size < BGP_MSG_UPDATE_MIN_SIZE) - || (type == BGP_MSG_NOTIFY && size < BGP_MSG_NOTIFY_MIN_SIZE) - || (type == BGP_MSG_KEEPALIVE && size != BGP_MSG_KEEPALIVE_MIN_SIZE) - || (type == BGP_MSG_ROUTE_REFRESH_NEW && size < BGP_MSG_ROUTE_REFRESH_MIN_SIZE) - || (type == BGP_MSG_ROUTE_REFRESH_OLD && size < BGP_MSG_ROUTE_REFRESH_MIN_SIZE) - || (type == BGP_MSG_CAPABILITY && size < BGP_MSG_CAPABILITY_MIN_SIZE)) - { - if (BGP_DEBUG (normal, NORMAL)) - plog_debug (session->log, - "%s bad message length - %d for %s", - session->host, size, - type == 128 ? "ROUTE-REFRESH" : - bgp_type_str[(int) type]); bgp_msg_notify_send_with_data (connection, bgp_session_eInvalid_msg, - BGP_NOTIFY_HEADER_ERR, - BGP_NOTIFY_HEADER_BAD_MESLEN, - (u_char *) notify_data_length, 2); + BGP_NOMC_HEADER, + BGP_NOMS_H_BAD_TYPE, + &type, 1); return -1; - } + } ; - return size - BGP_HEADER_SIZE; -} + /* Mimimum and maximum message length checks. */ + if ((size < min_size) || (size > BGP_MSG_MAX_L)) + return bgp_msg_header_bad_len(connection, type, size) ; -/* Marker check. */ -static int -bgp_msg_marker_all_one (struct stream *s, int length) -{ - int i; - - for (i = 0; i < length; i++) - if (s->data[i] != 0xff) - return 0; + connection->msg_type = type ; + connection->msg_size = size - BGP_MH_HEAD_L ; - return 1; + return connection->msg_size ; } -/* Deal with the BGP message. MUST remove from ibuf before returns ! */ +/*------------------------------------------------------------------------------ + * 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) + * + * Must have finished with ibuf when returns. + */ void bgp_msg_dispatch(bgp_connection connection) { - u_char type = 0; - bgp_size_t size; - - /* Get size and type again. */ - size = stream_getw_from (connection->ibuf, BGP_MARKER_SIZE); - type = stream_getc_from (connection->ibuf, BGP_MARKER_SIZE + 2); - - size -= BGP_HEADER_SIZE; + uint8_t type = connection->msg_size ; + bgp_size_t size = connection->msg_type ; /* Read rest of the packet and call each sort of packet routine */ switch (type) { - case BGP_MSG_OPEN: + case BGP_MT_OPEN: bgp_msg_open_receive (connection, size); break; - case BGP_MSG_UPDATE: + case BGP_MT_UPDATE: bgp_msg_update_receive (connection, size); break; - case BGP_MSG_NOTIFY: + case BGP_MT_NOTIFICATION: bgp_msg_notify_receive(connection, size); break; - case BGP_MSG_KEEPALIVE: + case BGP_MT_KEEPALIVE: bgp_msg_keepalive_receive(connection, size); break; - case BGP_MSG_ROUTE_REFRESH_NEW: - case BGP_MSG_ROUTE_REFRESH_OLD: + 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_MSG_CAPABILITY: + case BGP_MT_CAPABILITY: /* TODO: dynamic capability? */ #if 0 peer->dynamic_cap_in++; @@ -210,16 +222,32 @@ bgp_msg_dispatch(bgp_connection connection) break; default: assert(0); /* types already validated */ - } + } ; +} ; - /* remove message from ibuf */ - if (connection->ibuf) - stream_reset (connection->ibuf); -} +/*============================================================================== + * BGP OPEN message + * + * + * + */ + +static int +bgp_msg_open_option_parse (bgp_connection connection, bgp_notify notification, + sucker sr) ; +static int +bgp_msg_capability_option_parse (bgp_connection connection, + bgp_notify notification, sucker sr) ; +static int +bgp_msg_open_error(bgp_notify notification, bgp_nom_subcode_t subcode) ; -/* Receive BGP open packet and parse it into the session's - * open_recv - * return 0 OK +static int +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 @@ -228,822 +256,1029 @@ bgp_msg_open_receive (bgp_connection connection, bgp_size_t size) int ret; u_char version; u_char optlen; - as_t remote_as = 0; - as_t as4 = 0; struct in_addr remote_id; - int capability; - u_int8_t notify_data_remote_as[2]; - u_int8_t notify_data_remote_id[4]; - bgp_session session = connection->session; bgp_open_state open_recv; + struct stream* s ; + struct sucker ssr ; + unsigned holdtime ; + + /* Start with an unspecific OPEN notification */ + bgp_notify notification = bgp_notify_new(BGP_NOMC_OPEN, + BGP_NOMS_UNSPECIFIC, 0) ; - assert(session); + /* To receive the parsed open message */ + open_recv = connection->open_recv + = bgp_open_state_init_new(connection->open_recv) ; - /* To receive the parsed open message */ - session->open_recv = bgp_open_state_init_new(session->open_recv); - open_recv = session->open_recv; + /* Parse fixed part of the open packet */ + s = connection->ibuf ; - /* Parse open packet. */ - version = stream_getc (connection->ibuf); - memcpy (notify_data_remote_as, stream_pnt (connection->ibuf), 2); - open_recv->my_as = stream_getw (connection->ibuf); - open_recv->holdtime = stream_getw (connection->ibuf); - memcpy (notify_data_remote_id, stream_pnt (connection->ibuf), 4); - remote_id.s_addr = stream_get_ipv4 (connection->ibuf); + version = stream_getc (s); + open_recv->my_as2 = stream_getw (s); + open_recv->holdtime = stream_getw (s); + open_recv->bgp_id = stream_get_ipv4 (s); - /* Receive OPEN message log */ + open_recv->my_as = open_recv->my_as2 ; + + remote_id.s_addr = open_recv->bgp_id ; + + /* Receive OPEN message log */ if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s rcv OPEN, version %d, remote-as (in open) %u," " holdtime %d, id %s", - session->host, version, open_recv->my_as, open_recv->holdtime, + connection->host, version, + open_recv->my_as, open_recv->holdtime, inet_ntoa (remote_id)); - /* BEGIN to read the capability here, but don't do it yet */ - capability = 0; - optlen = stream_getc (connection->ibuf); - - if (optlen != 0) + /* Peer BGP version check. */ + if (version != BGP_VERSION_4) { - /* We need the as4 capability value *right now* because - * if it is there, we have not got the remote_as yet, and without - * that we do not know which peer is connecting to us now. - */ - as4 = bgp_msg_peek_for_as4_capability (connection, optlen); + if (BGP_DEBUG (normal, NORMAL)) + zlog_debug("%s bad protocol version, remote requested %d, local max %d", + connection->host, version, BGP_VERSION_4); + + bgp_msg_open_error(notification, BGP_NOMS_O_VERSION) ; + bgp_notify_append_w(notification, BGP_VERSION_4) ; + + goto reject ; } - /* Just in case we have a silly peer who sends AS4 capability set to 0 */ - if (open_recv->can_as4 && !as4) + /* Remote bgp_id may not be multicast, or the same as here */ + if (IN_MULTICAST(open_recv->bgp_id) || + (open_recv->bgp_id == connection->session->open_send->bgp_id)) { - zlog_err ("%s bad OPEN, got AS4 capability, but AS4 set to 0", - session->host); - bgp_msg_notify_send (connection, bgp_session_eOpen_reject, - BGP_NOTIFY_OPEN_ERR, - BGP_NOTIFY_OPEN_BAD_PEER_AS); - return -1; - } + zlog_debug ("%s rcv OPEN, *multicast* id %s", + connection->host, inet_ntoa (remote_id)) ; + bgp_msg_noms_o_bad_id(notification, open_recv->bgp_id) ; + goto reject ; + } ; + + /* From the rfc: Upon receipt of an OPEN message, a BGP speaker MUST + calculate the value of the Hold Timer by using the smaller of its + configured Hold Time and the Hold Time received in the OPEN message. + The Hold Time MUST be either zero or at least three seconds. An + implementation may reject connections on the basis of the Hold Time. + + See below where sets keepalive to hold / 3 !! + */ + if (open_recv->holdtime < 3 && open_recv->holdtime != 0) + { + bgp_msg_open_error(notification, BGP_NOMS_O_H_TIME) ; + goto reject ; + } ; + + /* Open option part parse */ + + optlen = stream_getc(s) ; + + if (BGP_DEBUG (normal, NORMAL)) + zlog_debug ("%s rcv OPEN w/ OPTION parameter len: %u", + connection->host, optlen) ; - if (remote_as == BGP_AS_TRANS) + if (optlen != stream_get_left(s)) { - /* Take the AS4 from the capability. We must have received the - * capability now! Otherwise we have a asn16 peer who uses - * BGP_AS_TRANS, for some unknown reason. - */ - if (as4 == BGP_AS_TRANS) + zlog_err ("%s bad OPEN, message length %u but option length %u", + connection->host, (unsigned)stream_get_endp(s), optlen) ; + bgp_msg_open_invalid(notification) ; + goto reject ; + } ; + + suck_init(&ssr, stream_pnt(s), optlen) ; + + ret = bgp_msg_open_option_parse (connection, notification, &ssr) ; + if (ret < 0) + goto reject ; + + /* Now worry about the AS number */ + + /* ASN == 0 is odd for AS2, error for AS4 */ + if (open_recv->my_as == 0) + { + if (open_recv->can_as4) + { + zlog_err ("%s [AS4] bad OPEN, got AS4 capability, but AS4 set to 0", + connection->host) ; + bgp_msg_open_error(notification, BGP_NOMS_O_BAD_AS) ; + goto reject ; + } + else + { + if (BGP_DEBUG (as4, AS4)) + zlog_debug ("%s [AS4] OPEN remote_as is 0 (not AS4 speaker)" + " odd, but proceeding.", connection->host) ; + } ; + } ; + + /* ASN = BGP_AS_TRANS is odd for AS2, error for AS4 */ + if (open_recv->my_as == BGP_ASN_TRANS) + { + if (open_recv->can_as4) { zlog_err ("%s [AS4] NEW speaker using AS_TRANS for AS4, not allowed", - session->host); - bgp_msg_notify_send (connection, bgp_session_eOpen_reject, - BGP_NOTIFY_OPEN_ERR, - BGP_NOTIFY_OPEN_BAD_PEER_AS); - return -1; + connection->host); + bgp_msg_open_error(notification, BGP_NOMS_O_BAD_AS) ; + goto reject ; } - - if (!as4 && BGP_DEBUG (as4, AS4)) - zlog_debug ("%s [AS4] OPEN remote_as is AS_TRANS, but no AS4." - " Odd, but proceeding.", session->host); - else if (as4 < BGP_AS_MAX && BGP_DEBUG (as4, AS4)) - zlog_debug ("%s [AS4] OPEN remote_as is AS_TRANS, but AS4 (%u) fits " - "in 2-bytes, very odd peer.", session->host, as4); - if (as4) - remote_as = as4; - } - else + else + { + if (BGP_DEBUG (as4, AS4)) + zlog_debug ("%s [AS4] OPEN remote_as is AS_TRANS (not AS4 speaker)" + " odd, but proceeding.", connection->host) ; + } ; + } ; + + /* Worry about my_as2 for AS4 speaker, if as2 != as4 */ + if ((open_recv->can_as4) && (open_recv->my_as != open_recv->my_as2)) { - /* We may have a partner with AS4 who has an asno < BGP_AS_MAX */ - /* If we have got the capability, peer->as4cap must match remote_as */ - if (open_recv->can_as4 && as4 != remote_as) + if (open_recv->my_as2 == BGP_ASN_TRANS) + { + if ((open_recv->my_as <= BGP_AS2_MAX) && BGP_DEBUG(as4, AS4)) + zlog_debug ("%s [AS4] OPEN remote_as is AS_TRANS," + " but AS4 (%u) fits in 2-bytes, very odd peer.", + connection->host, open_recv->my_as) ; + } + else { - /* raise error, log this, close session */ zlog_err ("%s bad OPEN, got AS4 capability, but remote_as %u" " mismatch with 16bit 'myasn' %u in open", - session->host, as4, remote_as); - bgp_msg_notify_send (connection, bgp_session_eOpen_reject, - BGP_NOTIFY_OPEN_ERR, - BGP_NOTIFY_OPEN_BAD_PEER_AS); - return -1; - } - } + connection->host, open_recv->my_as, open_recv->my_as2) ; - /* Set remote router-id */ - open_recv->bgp_id = remote_id.s_addr; + bgp_msg_open_error(notification, BGP_NOMS_O_BAD_AS) ; + goto reject ; + } ; + } ; - /* Peer BGP version check. */ - if (version != BGP_VERSION_4) - { - u_int8_t maxver = BGP_VERSION_4; - if (BGP_DEBUG (normal, NORMAL)) - zlog_debug ("%s bad protocol version, remote requested %d, local request %d", - session->host, version, BGP_VERSION_4); - bgp_msg_notify_send_with_data (connection, bgp_session_eOpen_reject, - BGP_NOTIFY_OPEN_ERR, - BGP_NOTIFY_OPEN_UNSUP_VERSION, - &maxver, 1); - return -1; - } - - /* TODO: How? Check neighbor as number. */ -#if 0 - if (remote_as != session->as) + /* Finally -- require the AS to be the configured AS */ + if (open_recv->my_as != connection->session->as_expected) { if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s bad OPEN, remote AS is %u, expected %u", - session->host, remote_as, session->as); - bgp_msg_notify_send_with_data (connection, bgp_session_eOpen_reject, - BGP_NOTIFY_OPEN_ERR, - BGP_NOTIFY_OPEN_BAD_PEER_AS, - notify_data_remote_as, 2); - return -1; - } -#endif + connection->host, open_recv->my_as, + connection->session->as_expected) ; - /* From the rfc: Upon receipt of an OPEN message, a BGP speaker MUST - calculate the value of the Hold Timer by using the smaller of its - configured Hold Time and the Hold Time received in the OPEN message. - The Hold Time MUST be either zero or at least three seconds. An - implementation may reject connections on the basis of the Hold Time. */ - - if (open_recv->holdtime < 3 && open_recv->holdtime != 0) - { - bgp_msg_notify_send (connection, bgp_session_eOpen_reject, - BGP_NOTIFY_OPEN_ERR, - BGP_NOTIFY_OPEN_UNACEP_HOLDTIME); - return -1; - } + bgp_msg_open_error(notification, BGP_NOMS_O_BAD_AS) ; + if (open_recv->can_as4) + bgp_notify_append_l(notification, open_recv->my_as) ; + else + bgp_notify_append_w(notification, open_recv->my_as) ; - /* Open option part parse. */ - if (optlen != 0) - { - ret = bgp_msg_open_option_parse (connection, optlen, &open_recv->can_capability); - if (ret < 0) - return ret; - } - else - { - if (BGP_DEBUG (normal, NORMAL)) - zlog_debug ("%s rcvd OPEN w/ OPTION parameter len: 0", - session->host); + goto reject ; } - bgp_fsm_event(connection, bgp_fsm_Receive_OPEN_message); + /*............................................................................ + * It's OK ! Update the connection and issue event. + */ + bgp_notify_free(notification) ; /* No further use for this */ - return 0; -} + holdtime = connection->session->open_send->holdtime ; -static as_t -bgp_msg_capability_as4 (bgp_connection connection, struct capability_header *hdr) -{ - as_t as4 = stream_getl (connection->ibuf); - bgp_session session = connection->session; - assert(session); + if (holdtime > open_recv->holdtime) + holdtime = open_recv->holdtime ; /* use smaller of theirs & ours */ + if (holdtime < 3) + holdtime = 0 ; /* no slip ups */ - if (BGP_DEBUG (as4, AS4)) - zlog_debug ("%s [AS4] about to set cap PEER_CAP_AS4_RCV, got as4 %u", - session->host, as4); + connection->hold_timer_interval = holdtime ; + connection->keepalive_timer_interval = holdtime / 3 ; - return as4; -} + 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; -/* peek into option, stores ASN to *as4 if the AS4 capability was found. - * Returns 0 if no as4 found, as4cap value otherwise. - */ -static as_t -bgp_msg_peek_for_as4_capability (bgp_connection connection, u_char length) -{ - struct stream *s = connection->ibuf; - size_t orig_getp = stream_get_getp (s); - size_t end = orig_getp + length; - as_t as4 = 0; - bgp_session session = connection->session; - assert(session); + bgp_fsm_event(connection, bgp_fsm_Receive_OPEN_message) ; - /* The full capability parser will better flag the error.. */ - if (STREAM_READABLE(s) < length) - return 0; + return 0; - if (BGP_DEBUG (as4, AS4)) - zlog_info ("%s [AS4] rcv OPEN w/ OPTION parameter len: %u," - " peeking for as4", - session->host, length); - /* the error cases we DONT handle, we ONLY try to read as4 out of - * correctly formatted options. + /*............................................................................ + * Failed. Reject the OPEN with the required notification. */ - while (stream_get_getp(s) < end) - { - u_char opt_type; - u_char opt_length; +reject: + bgp_fsm_raise_exception(connection, bgp_session_eOpen_reject, notification); - /* Check the length. */ - if (stream_get_getp (s) + 2 > end) - goto end; - - /* Fetch option type and length. */ - opt_type = stream_getc (s); - opt_length = stream_getc (s); - - /* Option length check. */ - if (stream_get_getp (s) + opt_length > end) - goto end; - - if (opt_type == BGP_OPEN_OPT_CAP) - { - unsigned long capd_start = stream_get_getp (s); - unsigned long capd_end = capd_start + opt_length; + return -1 ; +} ; - assert (capd_end <= end); +/*------------------------------------------------------------------------------ + * Set notification to BGP_NOMC_OPEN/BGP_NOMS_O_BAD_ID and set the data part + * to be the given bad id. + * + * Create notification if required. + */ +extern bgp_notify +bgp_msg_noms_o_bad_id(bgp_notify notification, bgp_id_t id) +{ + notification = bgp_notify_reset(notification, BGP_NOMC_OPEN, + BGP_NOMS_O_BAD_ID) ; + bgp_notify_append_data(notification, &id, 4) ; - while (stream_get_getp (s) < capd_end) - { - struct capability_header hdr; + return notification ; +} ; - if (stream_get_getp (s) + 2 > capd_end) - goto end; +/*------------------------------------------------------------------------------ + * Reset notification to BGP_NOMC_OPEN with the given subcode, and return -1. + */ +static int +bgp_msg_open_error(bgp_notify notification, bgp_nom_subcode_t subcode) +{ + bgp_notify_reset(notification, BGP_NOMC_OPEN, subcode) ; + return -1 ; +} ; - hdr.code = stream_getc (s); - hdr.length = stream_getc (s); +/*------------------------------------------------------------------------------ + * Reset notification to BGP_NOMC_OPEN/BGP_NOMS_UNSPECIFIC, and return -1. + */ +static int +bgp_msg_open_invalid(bgp_notify notification) +{ + return bgp_msg_open_error(notification, BGP_NOMS_UNSPECIFIC) ; +} ; - if ((stream_get_getp(s) + hdr.length) > capd_end) - goto end; +/*------------------------------------------------------------------------------ + * Add unsupported capability to notification. + * + * The sr points at the start of the capability value. + */ +static void +bgp_msg_capability_unsupported(bgp_notify notification, sucker sr) +{ + ptr_t p_cap ; + int cap_len ; - if (hdr.code == CAPABILITY_CODE_AS4) - { - if (hdr.length != CAPABILITY_CODE_AS4_LEN) - goto end; + if (notification->subcode != BGP_NOMS_O_CAPABILITY) + bgp_notify_reset(notification, BGP_NOMC_OPEN, BGP_NOMS_O_CAPABILITY) ; - if (BGP_DEBUG (as4, AS4)) - zlog_info ("[AS4] found AS4 capability, about to parse"); - as4 = stream_getl (connection->ibuf); - session->open_recv->can_as4 = 1; + cap_len = suck_total(sr) ; + p_cap = suck_start(sr) - BGP_CAP_MIN_L ; - goto end; - } - stream_forward_getp (s, hdr.length); - } - } - } + assert(*(p_cap + 1) == cap_len) ; -end: - stream_set_getp (s, orig_getp); - return as4; -} + bgp_notify_append_data(notification, p_cap, BGP_CAP_MIN_L + cap_len) ; +} ; -/* Parse open option */ +/*------------------------------------------------------------------------------ + * Parse OPEN message options part. + * + * Expects the notification to be set up: BGP_NOMC_OPEN, BGP_NOMS_UNSPECIFIC + * with no data, yet. + * + * Returns: -1 => error -- see notification + * 0 => OK, no capabilities + * 1 => OK, at least one capability + */ static int -bgp_msg_open_option_parse (bgp_connection connection, u_char length, int *capability) +bgp_msg_open_option_parse (bgp_connection connection, bgp_notify notification, + sucker sr) { - int ret; - u_char *error; - u_char error_data[BGP_MAX_PACKET_SIZE]; - struct stream *s = connection->ibuf; - size_t end = stream_get_getp (s) + length; - bgp_session session = connection->session; - assert(session); + int ret, capability ; + int left ; + bgp_session session = connection->session ; + bgp_open_state open_send = session->open_send ; + bgp_open_state open_recv = connection->open_recv ; - ret = 0; - error = error_data; + /* Prepare to read BGP OPEN message options */ - if (BGP_DEBUG (normal, NORMAL)) - zlog_debug ("%s rcv OPEN w/ OPTION parameter len: %u", - session->host, length); + ret = 0 ; /* OK so far */ + capability = 0 ; /* No capability option, yet */ - while (stream_get_getp(s) < end) + while ((left = suck_left(sr)) > 0) { - u_char opt_type; - u_char opt_length; + struct sucker ssr ; + u_char opt_type ; + u_char opt_length ; - /* Must have at least an OPEN option header */ - if (STREAM_READABLE(s) < 2) + /* Fetch option type and length, if possible */ + if ((left -= 2) > 0) { - zlog_info ("%s Option length error", session->host); - bgp_msg_notify_send (connection, bgp_session_eOpen_reject, - BGP_NOTIFY_CEASE, 0); - return -1; - } + opt_type = suck_b(sr); + opt_length = suck_b(sr); + left -= opt_length ; + } ; - /* Fetch option type and length. */ - opt_type = stream_getc (s); - opt_length = stream_getc (s); - - /* Option length check. */ - if (STREAM_READABLE (s) < opt_length) + /* Must not have exceeded available bytes */ + if (left < 0) { - zlog_info ("%s Option length error", session->host); - bgp_msg_notify_send (connection, bgp_session_eOpen_reject, - BGP_NOTIFY_CEASE, 0); - return -1; + zlog_info ("%s Option length error", connection->host); + return bgp_msg_open_invalid(notification) ; } if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s rcvd OPEN w/ optional parameter type %u (%s) len %u", - session->host, opt_type, + connection->host, opt_type, opt_type == BGP_OPEN_OPT_AUTH ? "Authentication" : opt_type == BGP_OPEN_OPT_CAP ? "Capability" : "Unknown", opt_length); + suck_push(sr, opt_length, &ssr) ; + switch (opt_type) { - case BGP_OPEN_OPT_AUTH: - bgp_msg_notify_send (connection, bgp_session_eOpen_reject, - BGP_NOTIFY_OPEN_ERR, - BGP_NOTIFY_OPEN_AUTH_FAILURE); - ret = -1; - break; - case BGP_OPEN_OPT_CAP: - ret = bgp_msg_capability_parse (connection, opt_length, &error); - *capability = 1; + case BGP_OPT_AUTH: + return bgp_msg_open_error(notification, BGP_NOMS_O_AUTH) ; + + case BGP_OPT_CAPS: + capability = 1 ; /* does => can */ + + ret = bgp_msg_capability_option_parse(connection, notification, sr) ; + if (ret < 0) + return bgp_msg_open_invalid(notification) ; + break; + default: - bgp_msg_notify_send (connection, bgp_session_eOpen_reject, - BGP_NOTIFY_OPEN_ERR, - BGP_NOTIFY_OPEN_UNSUP_PARAM); - ret = -1; - break; - } + return bgp_msg_open_error(notification, BGP_NOMS_O_OPTION) ; + } ; + + suck_pop(sr, &ssr) ; + } ; + + /* All OPEN option is parsed. + * + * Do "strict" capability checks: + * + * 1) if there were any unknown capabilities, or any AFI/SAFI which are + * unknown or are not configured, then that is now an error. + * + * 2) the local AFI/SAFI must be the same as the remote AFI/SAFI. + * + * TODO: verify that (2) should be checked *before* any "OVERRIDE". + */ + if (session->cap_strict) + { + /* Treat any unsuppprted capability as an error. */ + if (bgp_notify_get_subcode(notification) == BGP_NOMS_O_CAPABILITY) + return -1 ; - /* Parse error. To accumulate all unsupported capability codes, - bgp_capability_parse does not return -1 when encounter - unsupported capability code. To detect that, please check - error and erro_data pointer, like below. */ - if (ret < 0) - return -1; - } + /* Check local AFI/SAFI set is same as the remote one. */ + if (open_recv->can_mp_ext != open_send->can_mp_ext) + return bgp_msg_open_error(notification, BGP_NOMS_O_CAPABILITY) ; + } ; - /* All OPEN option is parsed. Check capability when strict compare - flag is enabled.*/ - if (session->cap_strict) + /* If there were any capabilities, and not going to override AFI/SAFI, + * then check that there is at least one AFI/SAFI in common. + */ + if (capability && ! session->cap_override) { - /* If Unsupported Capability exists. */ - if (error != error_data) + if ((open_recv->can_mp_ext & open_send->can_mp_ext) == 0) { - bgp_msg_notify_send_with_data (connection, bgp_session_eOpen_reject, - BGP_NOTIFY_OPEN_ERR, - BGP_NOTIFY_OPEN_UNSUP_CAPBL, - error_data, error - error_data); - return -1; - } + plog_err (connection->log, "%s [Error] No common capability", + connection->host) ; + if (bgp_notify_get_subcode(notification) != BGP_NOMS_O_CAPABILITY) + bgp_msg_open_error(notification, BGP_NOMS_O_CAPABILITY) ; - /* Check local capability does not negotiated with remote - peer. */ - if (session->open_recv->can_mp_ext != session->open_send->can_mp_ext) - { - bgp_msg_notify_send (connection, bgp_session_eOpen_reject, - BGP_NOTIFY_OPEN_ERR, - BGP_NOTIFY_OPEN_UNSUP_CAPBL); - return -1; + return -1 ; } - } + } ; - /* Check there is no common capability send Unsupported Capability - error. */ - if (*capability && ! session->cap_override) - { - if (session->open_recv->can_mp_ext == 0) - { - plog_err (session->log, "%s [Error] No common capability", session->host); + return connection->open_recv->can_capability = capability ; +} ; - if (error != error_data) +/*------------------------------------------------------------------------------ + * From IANA "Capability Codes (last updated 2009-08-04) Reference: [RFC5492]" + * + * Range Registration Procedures + * --------- -------------------------- + * 1- 63 IETF Review + * 64-127 First Come First Served + * 128-255 Reserved for Private Use (IANA does not assign) + * + * 1 Multiprotocol Extensions for BGP-4 [RFC2858] + * 2 Route Refresh Capability for BGP-4 [RFC2918] + * 3 Outbound Route Filtering Capability [RFC5291] + * 4 Multiple routes to a destination capability [RFC3107] + * 5 Extended Next Hop Encoding [RFC5549] + * 64 Graceful Restart Capability [RFC4724] + * 65 Support for 4-octet AS number capability [RFC4893] + * 66 Deprecated (2003-03-06) + * 67 Support for Dynamic Capability (capability specific) [Chen] + * 68 Multisession BGP Capability [Appanna] + * 69 ADD-PATH Capability [draft-ietf-idr-add-paths] + * + * 66 is, in fact, for draft-ietf-idr-dynamic-cap-02 of the Support for + * Dynamic Capability (capability specific) + * + * Supported: + * + * 1 BGP_CAN_MP_EXT -- Multiprotocol Extensions + * 2 BGP_CAN_R_REFRESH -- Route Refresh + * 3 BGP_CAN_ORF -- Outbound Route Filtering + * 64 BGP_CAN_G_RESTART -- Graceful Restart + * 65 BGP_CAN_AS4 -- AS4 + * 66 BGP_CAN_DYNAMIC_CAP_old -- Dynamic Capability (old form) + * 128 BGP_CAN_R_REFRESH_pre -- pre-RFC Route Refresh + * 130 BGP_CAN_ORF_pre -- pre-RFC Outbound Route Filtering + */ - bgp_msg_notify_send_with_data (connection, bgp_session_eOpen_reject, - BGP_NOTIFY_OPEN_ERR, - BGP_NOTIFY_OPEN_UNSUP_CAPBL, - error_data, error - error_data); - else - bgp_msg_notify_send (connection, bgp_session_eOpen_reject, - BGP_NOTIFY_OPEN_ERR, - BGP_NOTIFY_OPEN_UNSUP_CAPBL); - return -1; - } - } - return 0; -} +CONFIRM(BGP_CAP_MPE_L == sizeof (struct capability_mp_data)) ; +CONFIRM(BGP_CAP_RRF_L == CAPABILITY_CODE_REFRESH_LEN) ; +CONFIRM(BGP_CAP_ORFE_MIN_L == sizeof (struct capability_orf_entry)) ; +CONFIRM(BGP_CAP_GR_MIN_L == sizeof (struct capability_gr)) ; +CONFIRM(BGP_CAP_AS4_L == CAPABILITY_CODE_AS4_LEN) ; +CONFIRM(BGP_CAP_DYN_L == CAPABILITY_CODE_DYNAMIC_LEN) ; + +CONFIRM(BGP_CAN_MP_EXT == CAPABILITY_CODE_MP) ; +CONFIRM(BGP_CAN_R_REFRESH == CAPABILITY_CODE_REFRESH) ; +CONFIRM(BGP_CAN_ORF == CAPABILITY_CODE_ORF) ; +CONFIRM(BGP_CAN_G_RESTART == CAPABILITY_CODE_RESTART) ; +CONFIRM(BGP_CAN_AS4 == CAPABILITY_CODE_AS4) ; +CONFIRM(BGP_CAN_DYNAMIC_CAP_old == CAPABILITY_CODE_DYNAMIC) ; +CONFIRM(BGP_CAN_R_REFRESH_pre == CAPABILITY_CODE_REFRESH_OLD) ; +CONFIRM(BGP_CAN_ORF_pre == CAPABILITY_CODE_ORF_OLD) ; + +/* TODO: clarify value for BGP_CAN_DYNAMIC_CAP !! */ + +/* Minimum sizes for length field of each cap (so not inc. the header) */ +static const unsigned cap_minsizes[] = +{ + [BGP_CAN_MP_EXT] = BGP_CAP_MPE_L, + [BGP_CAN_R_REFRESH] = BGP_CAP_RRF_L, + [BGP_CAN_ORF] = BGP_CAP_ORFE_MIN_L, + [BGP_CAN_G_RESTART] = BGP_CAP_GR_MIN_L, + [BGP_CAN_AS4] = BGP_CAP_AS4_L, + [BGP_CAN_DYNAMIC_CAP_old] = BGP_CAP_DYN_L, + [BGP_CAN_DYNAMIC_CAP] = BGP_CAP_DYN_L, + [BGP_CAN_R_REFRESH_pre] = BGP_CAP_RRF_L, + [BGP_CAN_ORF_pre] = BGP_CAP_ORFE_MIN_L, +} ; + +static const unsigned cap_maxsizes[] = +{ + [BGP_CAN_MP_EXT] = BGP_CAP_MPE_L, + [BGP_CAN_R_REFRESH] = BGP_CAP_RRF_L, + [BGP_CAN_ORF] = BGP_CAP_MAX_L, /* variable */ + [BGP_CAN_G_RESTART] = BGP_CAP_MAX_L, /* variable */ + [BGP_CAN_AS4] = BGP_CAP_AS4_L, + [BGP_CAN_DYNAMIC_CAP_old] = BGP_CAP_DYN_L, + [BGP_CAN_DYNAMIC_CAP] = BGP_CAP_DYN_L, + [BGP_CAN_R_REFRESH_pre] = BGP_CAP_RRF_L, + [BGP_CAN_ORF_pre] = BGP_CAP_MAX_L, /* variable */ +} ; + +/* Forward references for parsing individual capabilities, return -1 if the + * capability is malformed or contains invalid values. + */ +static int +bgp_msg_capability_mp(bgp_connection connection, sucker sr) ; + +static int +bgp_msg_capability_orf (bgp_connection connection, uint8_t cap_code, sucker sr); + +static int +bgp_msg_capability_restart (bgp_connection connection, sucker sr) ; -/* Parse given capability. - * XXX: This is reading into a stream, but not using stream API +static int +bgp_msg_capability_as4 (bgp_connection connection, sucker sr) ; + +/*------------------------------------------------------------------------------ + * Set notification to malformed/invalid. + * + * Returns -1 ! */ static int -bgp_msg_capability_parse (bgp_connection connection, size_t length, u_char **error) +bgp_msg_capability_bad(bgp_notify notification) { - int ret; - struct stream *s = connection->ibuf; - size_t end = stream_get_getp (s) + length; - bgp_session session = connection->session; - bgp_open_state open_recv = session->open_recv; + bgp_notify_reset(notification, BGP_NOMC_OPEN, BGP_NOMS_UNSPECIFIC) ; + return -1 ; +} ; - assert (STREAM_READABLE (s) >= length); +/*------------------------------------------------------------------------------ + * Parse given capability option -- may contain multiple capabilities. + * + * Adjusts the open_recv open state according to the capabilities seen. + * + * Collects unsupported capabilities in the notification, where a + * BGP_NOMS_O_CAPABILITY message will be created. So, at the end of the + * process, can tell if there are any unsupported capabilities. + * + * The unsupported capabilities will be: + * + * * MP Extensions AFI/SAFI which are unknown or are not configured at + * this end. + * + * * any unknown capabilities < 128 + * + * If an invalid or malformed capability is found, the notification is set + * BGP_NOMS_UNSPECIFIC -- see bgp_msg_capability_bad() above. + * + * Returns: 0 => OK (but may have collected some unsupported capabilities) + * -1 => invalid or malformed + */ +static int +bgp_msg_capability_option_parse (bgp_connection connection, + bgp_notify notification, sucker sr) +{ + int ret, left ; + bgp_open_state open_recv = connection->open_recv ; - while (stream_get_getp (s) < end) + while ((left = suck_left(sr)) > 0) { - size_t start; - u_char *sp = stream_pnt (s); - struct capability_header caphdr; + struct sucker ssr ; + int cap_code ; + unsigned cap_length ; /* We need at least capability code and capability length. */ - if (stream_get_getp(s) + 2 > end) + if ((left -= 2) > 0) { - zlog_info ("%s Capability length error (< header)", session->host); - bgp_msg_notify_send (connection, bgp_session_eOpen_reject, - BGP_NOTIFY_CEASE, 0); - return -1; + cap_code = suck_b(sr); + cap_length = suck_b(sr); + left -= cap_length ; } - caphdr.code = stream_getc (s); - caphdr.length = stream_getc (s); - start = stream_get_getp (s); - - /* Capability length check sanity check. */ - if (start + caphdr.length > end) + if (left < 0) { - zlog_info ("%s Capability length error (< length)", session->host); - bgp_msg_notify_send (connection, bgp_session_eOpen_reject, - BGP_NOTIFY_CEASE, 0); - return -1; - } + zlog_info ("%s Capability length error (< header)", connection->host); + return bgp_msg_capability_bad(notification) ; + } ; if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s OPEN has %s capability (%u), length %u", - session->host, - LOOKUP (capcode_str, caphdr.code), - caphdr.code, caphdr.length); + connection->host, + LOOKUP (capcode_str, cap_code), + cap_code, cap_length) ; /* Length sanity check, type-specific, for known capabilities */ - switch (caphdr.code) + switch (cap_code) { - case CAPABILITY_CODE_MP: - case CAPABILITY_CODE_REFRESH: - case CAPABILITY_CODE_REFRESH_OLD: - case CAPABILITY_CODE_ORF: - case CAPABILITY_CODE_ORF_OLD: - case CAPABILITY_CODE_RESTART: - case CAPABILITY_CODE_AS4: - case CAPABILITY_CODE_DYNAMIC: + case BGP_CAN_MP_EXT: + case BGP_CAN_R_REFRESH: + case BGP_CAN_ORF: + case BGP_CAN_G_RESTART: + case BGP_CAN_AS4: + case BGP_CAN_DYNAMIC_CAP: + case BGP_CAN_R_REFRESH_pre: + case BGP_CAN_ORF_pre: /* Check length. */ - if (caphdr.length < cap_minsizes[caphdr.code]) + if ( (cap_length < cap_minsizes[cap_code]) || + (cap_length > cap_maxsizes[cap_code]) ) { + const char* tag = "" ; + if (cap_minsizes[cap_code] != cap_maxsizes[cap_code]) + tag = "at least " ; zlog_info ("%s %s Capability length error: got %u," - " expected at least %u", - session->host, - LOOKUP (capcode_str, caphdr.code), - caphdr.length, - (unsigned) cap_minsizes[caphdr.code]); - bgp_msg_notify_send (connection, bgp_session_eOpen_reject, - BGP_NOTIFY_CEASE, 0); - return -1; - } + " expected %s%u", + connection->host, + LOOKUP (capcode_str, cap_code), + cap_length, tag, + (unsigned) cap_minsizes[cap_code]) ; + return bgp_msg_capability_bad(notification) ; + /* invalid: stop dead */ + } ; + break ; /* we deliberately ignore unknown codes, see below */ default: - break; - } + break ; + } ; + + /* By this point the capability length is exactly right for the + * fixed length capabilities, at least the minimum length for the rest. + * Also, then capability fits within the capability option. + */ + suck_push(sr, cap_length, &ssr) ; - switch (caphdr.code) + ret = 0 ; + switch (cap_code) { - case CAPABILITY_CODE_MP: - { - /* Ignore capability when override-capability is set. */ - if (! session->cap_override) - { - /* Set negotiated value. */ - ret = bgp_msg_capability_mp (connection, &caphdr); - - /* Unsupported Capability. */ - if (ret < 0) - { - /* Store return data. */ - memcpy (*error, sp, caphdr.length + 2); - *error += caphdr.length + 2; - } - } - } + case BGP_CAN_MP_EXT: + /* Ignore capability when override-capability is set. + * + * NB: bgp_msg_capability_mp() returns > 0 if the AFI/SAFI is not + * recognised or is not one of the configured ones. + */ + if (! connection->session->cap_override) + ret = bgp_msg_capability_mp(connection, sr); break; - case CAPABILITY_CODE_REFRESH: - case CAPABILITY_CODE_REFRESH_OLD: - { - /* BGP refresh capability */ - if (caphdr.code == CAPABILITY_CODE_REFRESH_OLD) - open_recv->can_r_refresh |= bgp_cap_form_old; - else - open_recv->can_r_refresh |= bgp_cap_form_new; - } + + case BGP_CAN_R_REFRESH: + open_recv->can_r_refresh |= bgp_cap_form_new ; + break ; + + case BGP_CAN_R_REFRESH_pre: + open_recv->can_r_refresh |= bgp_cap_form_old; break; - case CAPABILITY_CODE_ORF: - case CAPABILITY_CODE_ORF_OLD: - if (bgp_msg_capability_orf (connection, &caphdr)) - return -1; + + case BGP_CAN_ORF: + case BGP_CAN_ORF_pre: + ret = bgp_msg_capability_orf(connection, cap_code, sr) ; break; - case CAPABILITY_CODE_RESTART: - if (bgp_msg_capability_restart (connection, &caphdr)) - return -1; + + case BGP_CAN_G_RESTART: + ret = bgp_msg_capability_restart(connection, sr) ; break; - case CAPABILITY_CODE_DYNAMIC: + + case BGP_CAN_DYNAMIC_CAP_old: open_recv->can_dynamic = 1; break; - case CAPABILITY_CODE_AS4: - /* Already handled as a special-case parsing of the capabilities - * at the beginning of OPEN processing. So we care not a jot - * for the value really, only error case. - */ - if (!bgp_msg_capability_as4 (connection, &caphdr)) - return -1; - break; + + case BGP_CAN_AS4: + ret = bgp_msg_capability_as4(connection, sr) ; + break; + default: - if (caphdr.code > 128) + if (cap_code >= 128) { /* We don't send Notification for unknown vendor specific capabilities. It seems reasonable for now... */ zlog_warn ("%s Vendor specific capability %d", - session->host, caphdr.code); + connection->host, cap_code); } else { zlog_warn ("%s unrecognized capability code: %d - ignored", - session->host, caphdr.code); - memcpy (*error, sp, caphdr.length + 2); - *error += caphdr.length + 2; + connection->host, cap_code) ; + ret = 1 ; /* collect unsupported capability */ } /* Add given unknown capability and its value */ - bgp_open_state_unknown_add(open_recv, caphdr.code, - stream_pnt (s), caphdr.length); + bgp_open_state_unknown_add(open_recv, cap_code, + suck_start(sr), suck_total(sr)) ; } - if (stream_get_getp(s) != (start + caphdr.length)) - { - if (stream_get_getp(s) > (start + caphdr.length)) - zlog_warn ("%s Cap-parser for %s read past cap-length, %u!", - session->host, LOOKUP (capcode_str, caphdr.code), - caphdr.length); - stream_set_getp (s, start + caphdr.length); - } + + if (ret < 0) + return bgp_msg_capability_bad(notification) ; + + if (ret > 0) + bgp_msg_capability_unsupported(notification, sr) ; + + suck_pop(sr, &ssr) ; } - return 0; -} -/* Set negotiated capability value. */ -static int -bgp_msg_capability_mp (bgp_connection connection, struct capability_header *hdr) + return 0 ; +} ; + +static qafx_bit_t +bgp_msg_afi_safi(sucker sr, struct iAFI_SAFI* mp) { - struct capability_mp_data mpc; - struct stream *s = connection->ibuf; - bgp_session session = connection->session; - bgp_open_state open_recv = session->open_recv; - bgp_open_state open_send = session->open_send; - qafx_bit_t qb; + mp->afi = suck_w(sr) ; + suck_x(sr) ; + mp->safi = suck_b(sr) ; + + return qafx_bit_from_iAFI_iSAFI(mp->afi, mp->safi) ; +} ; - assert(session); +/*------------------------------------------------------------------------------ + * Process value of Multiprotocol Extensions -- BGP_CAN_MP_EXT -- RFC2858 + * + * Capability is: AFI -- word + * reserved -- byte + * SAFI -- byte + * + * This is a fixed length capability, so that's been dealt with. + * + * Treats: invalid AFI/SAFI combinations ) + * unknown AFI/SAFI combinations ) unsupported capability + * unsupported AFI/SAFI combinations ) + * + * Sets any known AFI/SAFI combination in open_recv->can_mp_ext. + * + * Returns: 0 => OK -- AFI/SAFI is in the open_sent set + * 1 => -- AFI/SAFI is known, but not in the open_sent set + * 2 => -- AFI/SAFI is not known, may be invalid + */ +static int +bgp_msg_capability_mp(bgp_connection connection, sucker sr) +{ + struct iAFI_SAFI mp ; + qafx_bit_t qb ; - bgp_capability_mp_data (s, &mpc); + qb = bgp_msg_afi_safi(sr, &mp) ; if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s OPEN has MP_EXT CAP for afi/safi: %u/%u", - session->host, mpc.afi, mpc.safi); + connection->host, mp.afi, mp.safi) ; - if (!bgp_afi_safi_valid_indices (mpc.afi, &mpc.safi)) - return -1; + if (qb == 0) + { + zlog_warn ("Unknown afi/safi combination (%u/%u)", mp.afi, mp.safi) ; + return 2 ; + } ; - /* Now safi remapped, and afi/safi are valid array indices */ - qb = qafx_bit(qafx_num_from_qAFI_qSAFI(mpc.afi, mpc.safi)); + /* Now can register the capability */ + connection->open_recv->can_mp_ext |= qb; - open_recv->can_mp_ext |= qb; + /* Return: 0 => is in the open_send set + * 1 => is not + */ + return ((connection->session->open_send->can_mp_ext & qb) != 0) ? 0 : 1 ; +} ; - /* won't negotiate on afi/safi? */ - if ((open_send->can_mp_ext & qb) == 0) - return -1; +/*------------------------------------------------------------------------------ + * Process value of Outbound Route Filtering -- BGP_CAN_ORF -- RFC5291 + * + * Must have at least one ORF Entry, but may have several and each is of + * variable length. + * + * Requirement for at least one entry has already been checked. + * + * Returns: 0 => OK + * -1 => malformed ! + * + * NB: treats multiple ORF capabilities and multiple entries as additive. + * Does not track what AFI/SAFI and ORF types have been declared. + */ - return 0; -} +static int bgp_msg_capability_orf_entry(bgp_connection connection, + uint8_t cap_code, sucker sr) ; static int -bgp_msg_capability_restart (bgp_connection connection, struct capability_header *caphdr) +bgp_msg_capability_orf(bgp_connection connection, uint8_t cap_code, sucker sr) { - struct stream *s = connection->ibuf; - bgp_session session = connection->session; - bgp_open_state open_recv = session->open_recv; - bgp_open_state open_send = session->open_send; - u_int16_t restart_flag_time; - int restart_bit = 0; - size_t end = stream_get_getp (s) + caphdr->length; - - open_recv->can_g_restart = 1; - restart_flag_time = stream_getw(s); - if (CHECK_FLAG (restart_flag_time, RESTART_R_BIT)) - restart_bit = 1; - UNSET_FLAG (restart_flag_time, 0xF000); - open_recv->restart_time = restart_flag_time; - - if (BGP_DEBUG (normal, NORMAL)) - { - zlog_debug ("%s OPEN has Graceful Restart capability", session->host); - zlog_debug ("%s Peer has%srestarted. Restart Time : %d", - session->host, restart_bit ? " " : " not ", - open_recv->restart_time); - } - - while (stream_get_getp (s) + 4 < end) + while (suck_left(sr) > 0) { - afi_t afi = stream_getw (s); - safi_t safi = stream_getc (s); - u_char flag = stream_getc (s); - - if (!bgp_afi_safi_valid_indices (afi, &safi)) + if (suck_left(sr) < BGP_CAP_ORFE_MIN_L) { - if (BGP_DEBUG (normal, NORMAL)) - zlog_debug ("%s Addr-family %d/%d(afi/safi) not supported." - " Ignore the Graceful Restart capability", - session->host, afi, safi); - } - else - { - qafx_bit_t qb = qafx_bit(qafx_num_from_qAFI_qSAFI(afi, safi)); - - if (!(open_send->can_mp_ext & qb)) - { - if (BGP_DEBUG (normal, NORMAL)) - zlog_debug ("%s Addr-family %d/%d(afi/safi) not enabled." - " Ignore the Graceful Restart capability", - session->host, afi, safi); - } - else - { - if (BGP_DEBUG (normal, NORMAL)) - zlog_debug ("%s Address family %s is%spreserved", session->host, - afi_safi_print (afi, safi), - CHECK_FLAG (flag, RESTART_F_BIT) - ? " " : " not "); - - open_recv->can_preserve |= qb; - if (CHECK_FLAG (flag, RESTART_F_BIT)) - open_recv->has_preserved |= qb; - } - } - } + zlog_info ("%s ORF Capability length error," + " Cap length left %u", + connection->host, suck_left(sr)) ; + return -1; + } ; - return 0; -} + if (bgp_msg_capability_orf_entry (connection, cap_code, sr) == -1) + return -1; + } ; + return 0; +} ; +/* Process ORF Entry: + * + * Entry is: AFI -- word + * reserved -- byte + * SAFI -- byte + * number -- byte + * type -- byte ) repeated "number" times + * send/recv -- byte ) + * + * Returns: 0 => OK + * -1 => malformed + */ static int -bgp_msg_capability_orf_entry (bgp_connection connection, struct capability_header *hdr) +bgp_msg_capability_orf_entry(bgp_connection connection, uint8_t cap_code, + sucker sr) { - struct stream *s = connection->ibuf; - struct capability_orf_entry entry; - afi_t afi; - safi_t safi; - u_char type; - u_char mode; - int i; - bgp_session session = connection->session; - qafx_bit_t qb; - - assert(session); - - /* ORF Entry header */ - bgp_capability_mp_data (s, &entry.mpc); - entry.num = stream_getc (s); - afi = entry.mpc.afi; - safi = entry.mpc.safi; + iAFI_SAFI_t mp ; + int number ; + int length ; + sucker_t ssr ; + + bgp_open_state open_recv = connection->open_recv ; + qafx_bit_t qb ; + + /* ORF Entry header */ + qb = bgp_msg_afi_safi(sr, &mp) ; + number = suck_b(sr) ; if (BGP_DEBUG (normal, NORMAL)) - zlog_debug ("%s ORF Cap entry for afi/safi: %u/%u", - session->host, entry.mpc.afi, entry.mpc.safi); + zlog_debug ("%s ORF Cap entry for afi/safi: %u/%u %d types", + connection->host, mp.afi, mp.safi, number) ; - /* Check AFI and SAFI. */ - if (!bgp_afi_safi_valid_indices (entry.mpc.afi, &safi)) - { - zlog_info ("%s Addr-family %d/%d not supported." - " Ignoring the ORF capability", - session->host, entry.mpc.afi, entry.mpc.safi); - return 0; - } + /* Check AFI and SAFI. */ + if (qb == 0) + zlog_info ("%s Addr-family %d/%d not known." + " Ignoring the ORF capability", + connection->host, mp.afi, mp.safi) ; - /* validate number field */ - if (sizeof (struct capability_orf_entry) + (entry.num * 2) > hdr->length) + /* Validate number field */ + length = number * BGP_CAP_ORFT_L ; + + if (suck_left(sr) < length) { zlog_info ("%s ORF Capability entry length error," - " Cap length %u, num %u", - session->host, hdr->length, entry.num); - bgp_msg_notify_send (connection, bgp_session_eOpen_reject, - BGP_NOTIFY_CEASE, 0); + " Cap length left %u, num %u", + connection->host, suck_left(sr), number) ; return -1; - } + } ; + + /* Process the supported ORF types */ + + suck_push(sr, length, &ssr) ; - for (i = 0 ; i < entry.num ; i++) + while (number--) { - type = stream_getc(s); - mode = stream_getc(s); + qafx_bit_t qbs ; - /* ORF Mode error check */ + uint8_t type = suck_b(sr) ; + uint8_t mode = suck_b(sr) ; + + /* ORF Mode error check */ switch (mode) { - case ORF_MODE_BOTH: - case ORF_MODE_SEND: - case ORF_MODE_RECEIVE: + case BGP_CAP_ORFT_M_RECV: + case BGP_CAP_ORFT_M_SEND: + case BGP_CAP_ORFT_M_BOTH: break; default: - bgp_msg_capability_orf_not_support (session->host, afi, safi, type, mode); - continue; - } - /* ORF Type and afi/safi error checks */ - /* capcode versus type */ - switch (hdr->code) + zlog_info ("%s Invalid send/receive 'mode' value %d" + " in ORF capability", + connection->host, mode) ; + return -1 ; + } ; + + /* ORF Type and afi/safi sexing */ + qbs = 0 ; + switch (cap_code) { - case CAPABILITY_CODE_ORF: + case BGP_CAN_ORF: switch (type) { - case ORF_TYPE_PREFIX: - break; + case BGP_CAP_ORFT_T_PFIX: + open_recv->can_orf_prefix |= bgp_cap_form_new ; + qbs = qafx_ipv4_unicast_bit + | qafx_ipv4_multicast_bit + | qafx_ipv6_unicast_bit ; + break ; default: - bgp_msg_capability_orf_not_support (session->host, afi, safi, type, mode); - continue; + break ; } break; - case CAPABILITY_CODE_ORF_OLD: + case BGP_CAN_ORF_pre: switch (type) { - case ORF_TYPE_PREFIX_OLD: - break; + case BGP_CAP_ORFT_T_PFIX_pre: + open_recv->can_orf_prefix |= bgp_cap_form_old ; + qbs = qafx_ipv4_unicast_bit + | qafx_ipv4_multicast_bit + | qafx_ipv6_unicast_bit ; + break ; default: - bgp_msg_capability_orf_not_support (session->host, afi, safi, type, mode); - continue; + break ; } - break; + break ; default: - bgp_msg_capability_orf_not_support (session->host, afi, safi, type, mode); - continue; - } + break ; + } ; - /* AFI vs SAFI */ - if (!((afi == AFI_IP && safi == SAFI_UNICAST) - || (afi == AFI_IP && safi == SAFI_MULTICAST) - || (afi == AFI_IP6 && safi == SAFI_UNICAST))) + if ((qbs & qb) == 0) { - bgp_msg_capability_orf_not_support (session->host, afi, safi, type, mode); + 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; - } + } ; if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s OPEN has %s ORF capability" " as %s for afi/safi: %d/%d", - session->host, LOOKUP (orf_type_str, type), + connection->host, LOOKUP (orf_type_str, type), LOOKUP (orf_mode_str, mode), - entry.mpc.afi, safi); + mp.afi, mp.safi) ; + if (mode & BGP_CAP_ORFT_M_SEND) + open_recv->can_orf_prefix_send |= qb ; + if (mode & BGP_CAP_ORFT_M_RECV) + open_recv->can_orf_prefix_recv |= qb ; - if (hdr->code == CAPABILITY_CODE_ORF) - session->open_recv->can_orf_prefix |= bgp_cap_form_new; - else if (hdr->code == CAPABILITY_CODE_ORF_OLD) - session->open_recv->can_orf_prefix |= bgp_cap_form_old; - else - { - bgp_msg_capability_orf_not_support (session->host, afi, safi, type, mode); - continue; - } + confirm((BGP_CAP_ORFT_M_RECV & BGP_CAP_ORFT_M_SEND) == 0) ; - qb = qafx_bit(qafx_num_from_qAFI_qSAFI(afi, safi)); - switch (mode) - { - case ORF_MODE_BOTH: - session->open_recv->can_orf_prefix_send |= qb; - session->open_recv->can_orf_prefix_recv |= qb; - break; - case ORF_MODE_SEND: - session->open_recv->can_orf_prefix_send |= qb; - break; - case ORF_MODE_RECEIVE: - session->open_recv->can_orf_prefix_recv |= qb; - break; - } - } - return 0; -} + confirm((BGP_CAP_ORFT_M_SEND & BGP_CAP_ORFT_M_SEND) != 0) ; + confirm((BGP_CAP_ORFT_M_BOTH & BGP_CAP_ORFT_M_SEND) != 0) ; + confirm((BGP_CAP_ORFT_M_RECV & BGP_CAP_ORFT_M_RECV) != 0) ; + confirm((BGP_CAP_ORFT_M_BOTH & BGP_CAP_ORFT_M_RECV) != 0) ; + } ; + + /* Should now be exactly at the end. */ + suck_pop_exact(sr, &ssr) ; + + return 0; +} ; +/*------------------------------------------------------------------------------ + * Process value of Graceful Restart -- BGP_CAN_G_RESTART -- RFC2918 + * + * Capability is: time -- word + * AFI -- word ) + * SAFI -- byte ) repeated 0 or more times + * flag -- byte ) + * + * This is a variable length capability, minimum size already checked. + * + * The sr covers from the start to the end of the capability value. + * + * Returns: 0 => OK + * -1 => malformed ! + */ static int -bgp_msg_capability_orf (bgp_connection connection, struct capability_header *hdr) +bgp_msg_capability_restart (bgp_connection connection, sucker sr) { - struct stream *s = connection->ibuf; - size_t end = stream_get_getp (s) + hdr->length; + bgp_open_state open_recv = connection->open_recv; + u_int16_t restart_flag_time ; + int length ; - assert (stream_get_getp(s) + sizeof(struct capability_orf_entry) <= end); + length = suck_left(sr) ; /* total length of value, for reporting */ - /* We must have at least one ORF entry, as the caller has already done - * minimum length validation for the capability code - for ORF there must - * at least one ORF entry (header and unknown number of pairs of bytes). + /* RFC4724: "If more than one instance of the Graceful Restart Capability + * is carried in the capability advertisement, the receiver of + * the advertisement MUST ignore all but the last instance..." */ - do + + open_recv->can_g_restart = 1; + + /* Deal with the restart time and restarted flag */ + restart_flag_time = suck_w(sr) ; + + open_recv->has_restarted = (restart_flag_time & BGP_CAP_GR_T_R_FLAG) != 0 ; + open_recv->restart_time = restart_flag_time & BGP_CAP_GR_T_MASK ; + + open_recv->can_preserve = 0 ; + open_recv->has_preserved = 0 ; + + if (BGP_DEBUG (normal, NORMAL)) { - if (bgp_msg_capability_orf_entry (connection, hdr) == -1) - return -1; - } - while (stream_get_getp(s) + sizeof(struct capability_orf_entry) < end); + zlog_debug ("%s OPEN has Graceful Restart capability", connection->host); + zlog_debug ("%s Peer has%srestarted. Restart Time : %d", + connection->host, open_recv->has_restarted ? " " : " not ", + open_recv->restart_time); + } ; - return 0; -} + if ((suck_left(sr) % BGP_CAP_GRE_L) != 0) + { + zlog_info ("%s Graceful Restart Capability length error," + " Cap length %u", + connection->host, length); + return -1; + } ; -static void -bgp_msg_capability_orf_not_support (char *host, afi_t afi, safi_t safi, - u_char type, u_char mode) + while (suck_left(sr) > 0) + { + iAFI_SAFI_t mp ; + uint8_t flags ; + qafx_bit_t qb ; + + mp.afi = suck_w(sr) ; + mp.safi = suck_b(sr) ; + flags = suck_b(sr) ; + + qb = qafx_bit_from_iAFI_iSAFI(mp.afi, mp.safi) ; + + if (qb == 0) + { + if (BGP_DEBUG (normal, NORMAL)) + zlog_debug ("%s Addr-family %d/%d(afi/safi) not supported." + " Ignore the Graceful Restart capability", + connection->host, mp.afi, mp.safi); + } + else + { + /* Now can register the capability */ + + 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 ; + + if (BGP_DEBUG (normal, NORMAL)) + zlog_debug ("%s Address family %s is%spreserved", + connection->host, + afi_safi_print (mp.afi, mp.safi), + has ? " " : " not ") ; + } + else + { + if (BGP_DEBUG (normal, NORMAL)) + zlog_debug ("%s Addr-family %d/%d(afi/safi) not enabled." + " Ignore the Graceful Restart capability", + connection->host, mp.afi, mp.safi); + } ; + } ; + } ; + + return 0 ; +} ; + +/*------------------------------------------------------------------------------ + * Process value of AS4 capability -- BGP_CAN_AS4 -- RFC4893 + * + * Capability is: ASN -- long word (4 bytes) + * + * This is a fixed length capability, so that's been dealt with. + * + * Validation of ASN and cross-check against my_as2, done elsewhere. + * + * Returns: 0 => OK + */ +static int +bgp_msg_capability_as4 (bgp_connection connection, sucker sr) { - if (BGP_DEBUG (normal, NORMAL)) - zlog_debug ("%s Addr-family %d/%d has ORF type/mode %d/%d not supported", - host, afi, safi, type, mode); -} + bgp_open_state open_recv = connection->open_recv ; + + open_recv->can_as4 = 1 ; + open_recv->my_as = suck_l(sr) ; + + if (BGP_DEBUG (as4, AS4)) + zlog_debug ("%s [AS4] about to set cap PEER_CAP_AS4_RCV, got as4 %u", + connection->host, open_recv->my_as) ; + + return 0 ; +} ; + +/*============================================================================== + * BGP UPDATE message + */ /* Parse BGP Update packet. */ static int @@ -1054,23 +1289,26 @@ bgp_msg_update_receive (bgp_connection connection, bgp_size_t size) return 0; } -/* Keepalive treatment function -- get keepalive send keepalive */ +/*============================================================================== + * BGP KEEPALIVE message + */ static int bgp_msg_keepalive_receive (bgp_connection connection, bgp_size_t size) { - bgp_session session = connection->session; - - assert(session); - if (BGP_DEBUG (keepalive, KEEPALIVE)) - zlog_debug ("%s KEEPALIVE rcvd", session->host); + 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_Receive_KEEPALIVE_message); return 0; } -/* Notify message treatment function. */ +/*============================================================================== + * BGP NOTIFICATION message + */ static void bgp_msg_notify_receive (bgp_connection connection, bgp_size_t size) { @@ -1080,8 +1318,7 @@ bgp_msg_notify_receive (bgp_connection connection, bgp_size_t size) bgp_size_t expect = size - 2; notification = bgp_notify_new(code, subcode, expect); - notification = bgp_notify_append_data(notification, - stream_pnt(connection->ibuf), expect); + bgp_notify_append_data(notification, stream_pnt(connection->ibuf), expect); bgp_fsm_notification_exception(connection, notification); } @@ -1105,6 +1342,6 @@ bgp_msg_notify_send_with_data (bgp_connection connection, { bgp_notify notification; notification = bgp_notify_new(code, sub_code, datalen); - notification = bgp_notify_append_data(notification, data, datalen); + bgp_notify_append_data(notification, data, datalen); bgp_fsm_raise_exception(connection, except, notification); } diff --git a/bgpd/bgp_msg_read.h b/bgpd/bgp_msg_read.h index f846453f..100cd597 100644 --- a/bgpd/bgp_msg_read.h +++ b/bgpd/bgp_msg_read.h @@ -24,6 +24,7 @@ #define BGP_MSG_READ_H_ #include "bgpd/bgp_common.h" +#include "bgpd/bgp_notification.h" extern bgp_size_t bgp_msg_get_mlen(uint8_t* p) ; @@ -34,4 +35,7 @@ bgp_msg_check_header(bgp_connection connection); extern void bgp_msg_dispatch(bgp_connection connection); +extern bgp_notify +bgp_msg_noms_o_bad_id(bgp_notify notification, bgp_id_t id) ; + #endif /* BGP_MSG_READ_H_ */ diff --git a/bgpd/bgp_msg_write.c b/bgpd/bgp_msg_write.c index c321df59..ce4bf1b3 100644 --- a/bgpd/bgp_msg_write.c +++ b/bgpd/bgp_msg_write.c @@ -127,10 +127,10 @@ bgp_msg_write_notification(bgp_connection connection, bgp_notify notification) while (length--) { sprintf (c, form, *p++) ; - text_form = bgp_notify_append_data(text_form, c, strlen(c)) ; + bgp_notify_append_data(text_form, c, strlen(c)) ; form = " %02x" ; } ; - text_form = bgp_notify_append_data(text_form, "\0", 1) ; + bgp_notify_append_data(text_form, "\0", 1) ; /* TODO: restore bgp_notify_print */ #if 0 @@ -231,11 +231,9 @@ bgp_msg_send_open(bgp_connection connection, bgp_open_state open_state) if (BGP_DEBUG (normal, NORMAL)) { - struct in_addr bgp_id ; char buf[INET_ADDRSTRLEN] ; - bgp_id.s_addr = htonl(open_state->bgp_id) ; - inet_ntop(AF_INET, &bgp_id.s_addr, buf, INET_ADDRSTRLEN) ; + inet_ntop(AF_INET, &open_state->bgp_id, buf, INET_ADDRSTRLEN) ; zlog_debug ("%s sending OPEN, version %d, my as %u, holdtime %d, id %s", connection->host, BGP_VERSION_4, open_state->my_as, @@ -610,7 +608,7 @@ 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->route_refresh_pre) + if ((orf_type == BGP_ORF_T_PREFIX) && connection->orf_prefix_pre) orf_type_sent = BGP_ORF_T_PREFIX_pre ; stream_putc(s, orf_type_sent) ; /* ORF entries type */ diff --git a/bgpd/bgp_notification.c b/bgpd/bgp_notification.c index 6676b346..2dc6952e 100644 --- a/bgpd/bgp_notification.c +++ b/bgpd/bgp_notification.c @@ -22,11 +22,13 @@ */ #include <string.h> +#include <netinet/in.h> #include "lib/zassert.h" #include "lib/memory.h" #include "bgpd/bgp_notification.h" +#include "bgpd/bgp_open_state.h" /*============================================================================== * A bgp_notify structure encapsulates the contents of a BGP NOTIFICATION @@ -41,9 +43,9 @@ * Rounds up to multiple of 32, such that is always at least 16 bytes available. */ static inline bgp_size_t -bgp_notify_size(bgp_size_t length) +bgp_notify_size(bgp_size_t size) { - return sizeof(struct bgp_notify) + (((length + 32 + 16 - 1) / 32) * 32) ; + return (size == 0) ? 0 : ((size + 32 + 16 - 1) / 32) * 32 ; } ; /*============================================================================== @@ -60,15 +62,19 @@ bgp_notify_new(bgp_nom_code_t code, bgp_nom_subcode_t subcode, bgp_size_t expect) { bgp_notify notification ; - bgp_size_t size = bgp_notify_size(expect) ; - notification = XCALLOC(MTYPE_BGP_NOTIFY, size) ; + notification = XCALLOC(MTYPE_BGP_NOTIFY, sizeof(struct bgp_notify)) ; notification->code = code ; notification->subcode = subcode ; - notification->size = size ; + notification->size = bgp_notify_size(expect) ; notification->length = 0 ; + if (notification->size != 0) + notification->data = XCALLOC(MTYPE_TMP, notification->size) ; + else + notification->data = NULL ; + return notification ; } ; @@ -81,7 +87,11 @@ extern void bgp_notify_free(bgp_notify notification) { if (notification != NULL) - XFREE(MTYPE_BGP_NOTIFY, notification) ; + { + if (notification->data != NULL) + XFREE(MTYPE_TMP, notification->data) ; + XFREE(MTYPE_BGP_NOTIFY, notification) ; + } ; } ; /*------------------------------------------------------------------------------ @@ -91,16 +101,25 @@ extern bgp_notify bgp_notify_dup(bgp_notify notification) { bgp_notify duplicate ; - bgp_size_t size ; if (notification == NULL) return NULL ; - size = bgp_notify_size(notification->length) ; - duplicate = XMALLOC(MTYPE_BGP_NOTIFY, size) ; + duplicate = XMALLOC(MTYPE_BGP_NOTIFY, sizeof(struct bgp_notify)) ; + *duplicate = *notification ; - memcpy((void*)duplicate, (void*)notification, size) ; - duplicate->size = size ; + if (notification->length == 0) + { + duplicate->size = 0 ; + duplicate->data = NULL ; + } + else + { + bgp_size_t size = bgp_notify_size(duplicate->length) ; + duplicate->size = size ; + duplicate->data = XCALLOC(MTYPE_TMP, size) ; + memcpy(duplicate->data, notification->data, duplicate->length) ; + } ; return duplicate ; } ; @@ -113,8 +132,8 @@ bgp_notify_dup(bgp_notify notification) extern void bgp_notify_unset(bgp_notify* p_notification) { - if (*p_notification != NULL) - XFREE(MTYPE_BGP_NOTIFY, *p_notification) ; /* sets *p_notification NULL */ + bgp_notify_free(*p_notification) ; /* free anything that's there */ + *p_notification = NULL ; } ; /*------------------------------------------------------------------------------ @@ -159,22 +178,44 @@ bgp_notify_set_mov(bgp_notify* p_dst, bgp_notify* p_src) } ; /*============================================================================== + * Set new Code and Subcode and discard and data accumulated so far. + */ +extern bgp_notify +bgp_notify_reset(bgp_notify notification, bgp_nom_code_t code, + bgp_nom_subcode_t subcode) +{ + if (notification == NULL) + return bgp_notify_new(code, subcode, 0) ; + + notification->code = code ; + notification->subcode = subcode ; + notification->length = 0 ; + + return notification ; +} ; + +/*============================================================================== * Append data to given notification * * Copes with zero length append. * * NB: returns possibly NEW ADDRESS of the notification. */ -extern bgp_notify +extern void bgp_notify_append_data(bgp_notify notification, const void* data, bgp_size_t len) { bgp_size_t new_length = notification->length + len ; - if ((sizeof(struct bgp_notify) + new_length) > notification->size) + if (new_length > notification->size) { bgp_size_t size = bgp_notify_size(new_length) ; - notification = XREALLOC(MTYPE_BGP_NOTIFY, notification, size) ; + + if (notification->size == 0) + notification->data = XCALLOC(MTYPE_TMP, size) ; + else + notification->data = XREALLOC(MTYPE_TMP, notification->data, size) ; + memset((char*)notification + notification->size, 0, size - notification->size) ; notification->size = size ; @@ -184,6 +225,33 @@ bgp_notify_append_data(bgp_notify notification, const void* data, memcpy((char*)(notification->data) + notification->length, data, len) ; notification->length = new_length ; +} ; - return notification ; +/*------------------------------------------------------------------------------ + * Append one byte + */ +extern void +bgp_notify_append_b(bgp_notify notification, uint8_t b) +{ + bgp_notify_append_data(notification, &b, 1) ; +} ; + +/*------------------------------------------------------------------------------ + * Append one word (uint16_t), in network byte order + */ +extern void +bgp_notify_append_w(bgp_notify notification, uint16_t w) +{ + w = htons(w) ; + bgp_notify_append_data(notification, &w, 2) ; +} ; + +/*------------------------------------------------------------------------------ + * Append one long (uint32_t), in network byte order + */ +extern void +bgp_notify_append_l(bgp_notify notification, uint32_t l) +{ + l = htonl(l) ; + bgp_notify_append_data(notification, &l, 4) ; } ; diff --git a/bgpd/bgp_notification.h b/bgpd/bgp_notification.h index 4d8d4737..f225b492 100644 --- a/bgpd/bgp_notification.h +++ b/bgpd/bgp_notification.h @@ -49,7 +49,7 @@ struct bgp_notify bgp_size_t length ; bgp_size_t size ; - char data[] ; + ptr_t data ; } ; /*============================================================================== @@ -158,9 +158,19 @@ bgp_notify_set_subcode(bgp_notify notification, bgp_nom_subcode_t subcode) } ; extern bgp_notify +bgp_notify_reset(bgp_notify notification, bgp_nom_code_t code, + bgp_nom_subcode_t subcode) ; +extern void bgp_notify_append_data(bgp_notify notification, const void* data, bgp_size_t len) ; +extern void +bgp_notify_append_b(bgp_notify notification, uint8_t b) ; +extern void +bgp_notify_append_w(bgp_notify notification, uint16_t w) ; + +extern void +bgp_notify_append_l(bgp_notify notification, uint32_t l) ; Inline bgp_nom_code_t bgp_notify_get_code(bgp_notify notification) diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h index 9139c550..038c7c72 100644 --- a/bgpd/bgp_open.h +++ b/bgpd/bgp_open.h @@ -41,7 +41,7 @@ struct capability_mp_data }; #pragma pack(1) -struct capability_orf_entry +struct capability_orf_entry { struct capability_mp_data mpc; u_char num; @@ -90,13 +90,13 @@ struct capability_gr /* Cooperative Route Filtering Capability. */ /* ORF Type */ -#define ORF_TYPE_PREFIX 64 +#define ORF_TYPE_PREFIX 64 #define ORF_TYPE_PREFIX_OLD 128 /* ORF Mode */ -#define ORF_MODE_RECEIVE 1 -#define ORF_MODE_SEND 2 -#define ORF_MODE_BOTH 3 +#define ORF_MODE_RECEIVE 1 +#define ORF_MODE_SEND 2 +#define ORF_MODE_BOTH 3 /* Capability Message Action. */ #define CAPABILITY_ACTION_SET 0 @@ -108,7 +108,6 @@ struct capability_gr extern const struct message capcode_str[]; extern const int capcode_str_max; -extern const size_t cap_minsizes[]; extern const struct message orf_type_str[]; extern const int orf_type_str_max; diff --git a/bgpd/bgp_open_state.c b/bgpd/bgp_open_state.c index a8f880af..3be152cc 100644 --- a/bgpd/bgp_open_state.c +++ b/bgpd/bgp_open_state.c @@ -87,6 +87,21 @@ bgp_open_state_unset(bgp_open_state* p_state) *p_state = NULL ; } ; +/*------------------------------------------------------------------------------ + * Set pointer to open_state and unset source pointer + * + * Frees any existing open_state at the destination. + * + * NB: responsibility for the open_state structure passes to the destination. + */ +extern void +bgp_open_state_set_mov(bgp_open_state* p_dst, bgp_open_state* p_src) +{ + bgp_open_state_free(*p_dst) ; + *p_dst = *p_src ; + *p_src = NULL ; +} ; + /*============================================================================== * Construct new bgp_open_state for the given peer -- allocate if required. * @@ -124,6 +139,9 @@ bgp_peer_open_state_init_new(bgp_open_state state, bgp_peer peer) /* Announce self as AS4 speaker if required */ state->can_as4 = ((peer->cap & PEER_CAP_AS4_ADV) != 0) ; + state->my_as2 = (state->my_as > BGP_AS2_MAX ) ? BGP_ASN_TRANS + : state->my_as ; + /* Fill in the supported AFI/SAFI */ for (afi = qAFI_min ; afi <= qAFI_max ; ++afi) @@ -169,10 +187,10 @@ bgp_peer_open_state_init_new(bgp_open_state state, bgp_peer peer) state->restart_time = 0 ; } ; - /* TODO: check not restarting and not preserving forwarding state (?) */ + /* TODO: check not has restarted and not preserving forwarding state (?) */ state->can_preserve = 0 ; /* cannot preserve forwarding */ state->has_preserved = 0 ; /* has not preserved forwarding */ - state->restarting = 0 ; /* is not restarting */ + state->has_restarted = 0 ; /* has not restarted */ return state; } @@ -231,8 +249,10 @@ bgp_peer_open_state_receive(bgp_peer peer) bgp_session session = peer->session; bgp_open_state open_send = session->open_send; bgp_open_state open_recv = session->open_recv; - int afi; - int safi; + qAFI_t afi; + qSAFI_t safi; + qafx_bit_t qbs ; + int recv ; /* Check neighbor as number. */ assert(open_recv->my_as == peer->as); @@ -262,19 +282,36 @@ bgp_peer_open_state_receive(bgp_peer peer) if (open_recv->can_as4) SET_FLAG (peer->cap, PEER_CAP_AS4_RCV); - /* AFI/SAFI */ - /* Ignore capability when override-capability is set. */ + /* AFI/SAFI -- as received, or assumed or overridden */ + + if (!open_recv->can_capability || + CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) + { + /* There were no capabilities, or are OVERRIDING AFI/SAFI, so force + * not having received any AFI/SAFI, but apply this set. + */ + recv = 0 ; + qbs = qafx_ipv4_unicast_bit | qafx_ipv4_multicast_bit | + qafx_ipv6_unicast_bit | qafx_ipv6_multicast_bit | + qafx_ipv4_mpls_vpn_bit ; + } + else + { + /* Use the AFI/SAFI received, if any. */ + recv = 1 ; + qbs = open_recv->can_mp_ext ; + } + if (! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) { for (afi = qAFI_min ; afi <= qAFI_max ; ++afi) for (safi = qSAFI_min ; safi <= qSAFI_max ; ++safi) { - qafx_bit_t qb = qafx_bit(qafx_num_from_qAFI_qSAFI(afi, safi)); - if (qb & open_recv->can_mp_ext) + qafx_bit_t qb = qafx_bit_from_qAFI_qSAFI(afi, safi) ; + if (qb & qbs) { - peer->afc_recv[afi][safi] = 1; - assert(peer->afc[afi][safi]); - peer->afc_nego[afi][safi] = 1; + peer->afc_recv[afi][safi] = recv ; + peer->afc_nego[afi][safi] = peer->afc[afi][safi] ; } } } @@ -289,7 +326,7 @@ bgp_peer_open_state_receive(bgp_peer peer) for (afi = qAFI_min ; afi <= qAFI_max ; ++afi) for (safi = qSAFI_min ; safi <= qSAFI_max ; ++safi) { - qafx_bit_t qb = qafx_bit(qafx_num_from_qAFI_qSAFI(afi, safi)); + qafx_bit_t qb = qafx_bit_from_qAFI_qSAFI(afi, safi); if (qb & open_recv->can_orf_prefix_send) SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV); if (qb & open_recv->can_orf_prefix_recv) @@ -320,7 +357,7 @@ bgp_peer_open_state_receive(bgp_peer peer) for (afi = qAFI_min ; afi <= qAFI_max ; ++afi) for (safi = qSAFI_min ; safi <= qSAFI_max ; ++safi) { - qafx_bit_t qb = qafx_bit(qafx_num_from_qAFI_qSAFI(afi, safi)); + qafx_bit_t qb = qafx_bit_from_qAFI_qSAFI(afi, safi); if (peer->afc[afi][safi] && (qb & open_recv->can_g_restart)) { SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV); @@ -334,14 +371,4 @@ bgp_peer_open_state_receive(bgp_peer peer) #if 0 int restarting ; /* Restart State flag */ #endif - - /* Override capability. */ - if (!open_recv->can_capability || CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) - { - peer->afc_nego[AFI_IP][SAFI_UNICAST] = peer->afc[AFI_IP][SAFI_UNICAST]; - peer->afc_nego[AFI_IP][SAFI_MULTICAST] = peer->afc[AFI_IP][SAFI_MULTICAST]; - peer->afc_nego[AFI_IP6][SAFI_UNICAST] = peer->afc[AFI_IP6][SAFI_UNICAST]; - peer->afc_nego[AFI_IP6][SAFI_MULTICAST] = peer->afc[AFI_IP6][SAFI_MULTICAST]; - } - } diff --git a/bgpd/bgp_open_state.h b/bgpd/bgp_open_state.h index e9529208..413fc07d 100644 --- a/bgpd/bgp_open_state.h +++ b/bgpd/bgp_open_state.h @@ -63,15 +63,30 @@ struct bgp_cap_unknown /* to capture unknown capability */ uint8_t value[] ; } ; +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 ; +} ; + struct bgp_open_state { as_t my_as ; /* generic ASN */ unsigned holdtime ; /* in seconds */ - bgp_id_ht bgp_id ; /* an IPv4 address as *host* uint32_t */ + bgp_id_t bgp_id ; /* an IPv4 address -- *network order* */ - int can_capability ; /* false => don't send capabilities */ + int can_capability ; /* false => don't do capabilities */ int can_as4 ; /* true/false */ + as2_t my_as2 ; /* AS2 from OPEN message */ qafx_set_t can_mp_ext ; /* will accept, may send these */ @@ -87,7 +102,7 @@ struct bgp_open_state qafx_set_t can_preserve ; /* can preserve forwarding for these */ qafx_set_t has_preserved ; /* has preserved forwarding for these */ - int restarting ; /* Restart State flag */ + int has_restarted ; /* Restart State flag */ int restart_time ; /* Restart Time in seconds */ struct vector unknowns ; /* list of bgp_cap_unknown */ @@ -107,6 +122,9 @@ extern void bgp_open_state_unset(bgp_open_state* state) ; extern void +bgp_open_state_set_mov(bgp_open_state* p_dst, bgp_open_state* p_src) ; + +extern void bgp_open_state_unknown_add(bgp_open_state state, uint8_t code, void* value, bgp_size_t length) ; extern int diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 7814e111..2456706f 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -827,7 +827,7 @@ bgp_notify_send_with_data (struct peer *peer, u_char code, u_char sub_code, { bgp_notify notification; notification = bgp_notify_new(code, sub_code, datalen); - notification = bgp_notify_append_data(notification, data, datalen); + bgp_notify_append_data(notification, data, datalen); /* For debug */ bgp_notify_print (peer, notification, "sending"); diff --git a/bgpd/bgp_session.h b/bgpd/bgp_session.h index 2de8d931..236f6d0d 100644 --- a/bgpd/bgp_session.h +++ b/bgpd/bgp_session.h @@ -125,13 +125,14 @@ struct bgp_session /* The Routeing Engine sets open_send and clears open_recv before enabling * the session, and may not change them while sEnabled/sEstablished. * - * The BGP Engine sets open_recv before setting the session sEstablished, - * and will not touch it thereafter. + * The as_expected is the AS configured for the far end -- which is what + * expect to see in the incoming OPEN. * - * So: the Routeing Engine may use open_recv once the session is - * sEstablished. + * The BGP Engine sets open_recv signalling the session eEstablished, and + * will not touch it thereafter. */ bgp_open_state open_send ; /* how to open the session */ + as_t as_expected ; /* who to open with */ bgp_open_state open_recv ; /* set when session Established */ /* The following are set by the Routeing Engine before a session is @@ -159,20 +160,17 @@ struct bgp_session /* These are set by the Routeing Engine before a session is enabled, * but are affected by the capabilities received in the OPEN message. * - * The Routeing Engine may read these once sEstablished (under mutex). - * - * In sStopped state these reflect the last state of the session. + * When the session is established, the BGP Engine sets these. */ unsigned hold_timer_interval ; /* subject to negotiation */ unsigned keepalive_timer_interval ; /* subject to negotiation */ flag_t as4 ; /* set by OPEN */ flag_t route_refresh_pre ; /* use pre-RFC version */ + flag_t orf_prefix_pre ; /* use pre-RFC version */ /* These are cleared by the Routeing Engine before a session is enabled, * and set by the BGP Engine when the session is established. - * - * In sStopped state these reflect the last state of the session. */ union sockunion* su_local ; /* set when session Established */ union sockunion* su_remote ; /* set when session Established */ diff --git a/lib/distribute.c b/lib/distribute.c index 242a225c..6e7ccc67 100644 --- a/lib/distribute.c +++ b/lib/distribute.c @@ -34,7 +34,7 @@ struct hash *disthash; /* Hook functions. */ void (*distribute_add_hook) (struct distribute *); void (*distribute_delete_hook) (struct distribute *); - + static struct distribute * distribute_new (void) { @@ -68,11 +68,18 @@ distribute_lookup (const char *ifname) struct distribute key; struct distribute *dist; + union { + const char* waxon ; + char* waxoff ; + } miyagi ; + + miyagi.waxon = ifname ; + /* temporary reference */ - key.ifname = (char *)ifname; + key.ifname = miyagi.waxoff ; dist = hash_lookup (disthash, &key); - + return dist; } @@ -107,9 +114,16 @@ distribute_get (const char *ifname) { struct distribute key; + union { + const char* waxon ; + char* waxoff ; + } miyagi ; + + miyagi.waxon = ifname ; + /* temporary reference */ - key.ifname = (char *)ifname; - + key.ifname = miyagi.waxoff ; + return hash_get (disthash, &key, (void * (*) (void *))distribute_hash_alloc); } @@ -138,10 +152,10 @@ distribute_cmp (const struct distribute *dist1, const struct distribute *dist2) return 1; return 0; } - + /* Set access-list name to the distribute list. */ static struct distribute * -distribute_list_set (const char *ifname, enum distribute_type type, +distribute_list_set (const char *ifname, enum distribute_type type, const char *alist_name) { struct distribute *dist; @@ -163,14 +177,14 @@ distribute_list_set (const char *ifname, enum distribute_type type, /* Apply this distribute-list to the interface. */ (*distribute_add_hook) (dist); - + return dist; } /* Unset distribute-list. If matched distribute-list exist then return 1. */ static int -distribute_list_unset (const char *ifname, enum distribute_type type, +distribute_list_unset (const char *ifname, enum distribute_type type, const char *alist_name) { struct distribute *dist; @@ -187,7 +201,7 @@ distribute_list_unset (const char *ifname, enum distribute_type type, return 0; free (dist->list[DISTRIBUTE_IN]); - dist->list[DISTRIBUTE_IN] = NULL; + dist->list[DISTRIBUTE_IN] = NULL; } if (type == DISTRIBUTE_OUT) @@ -198,7 +212,7 @@ distribute_list_unset (const char *ifname, enum distribute_type type, return 0; free (dist->list[DISTRIBUTE_OUT]); - dist->list[DISTRIBUTE_OUT] = NULL; + dist->list[DISTRIBUTE_OUT] = NULL; } /* Apply this distribute-list to the interface. */ @@ -241,7 +255,7 @@ distribute_list_prefix_set (const char *ifname, enum distribute_type type, /* Apply this distribute-list to the interface. */ (*distribute_add_hook) (dist); - + return dist; } @@ -265,7 +279,7 @@ distribute_list_prefix_unset (const char *ifname, enum distribute_type type, return 0; free (dist->prefix[DISTRIBUTE_IN]); - dist->prefix[DISTRIBUTE_IN] = NULL; + dist->prefix[DISTRIBUTE_IN] = NULL; } if (type == DISTRIBUTE_OUT) @@ -276,7 +290,7 @@ distribute_list_prefix_unset (const char *ifname, enum distribute_type type, return 0; free (dist->prefix[DISTRIBUTE_OUT]); - dist->prefix[DISTRIBUTE_OUT] = NULL; + dist->prefix[DISTRIBUTE_OUT] = NULL; } /* Apply this distribute-list to the interface. */ @@ -401,7 +415,7 @@ DEFUN (distribute_list, dist = distribute_list_set (argv[2], type, argv[0]); return CMD_SUCCESS; -} +} ALIAS (distribute_list, ipv6_distribute_list_cmd, @@ -442,7 +456,7 @@ DEFUN (no_districute_list, no_distribute_list_cmd, return CMD_WARNING; } return CMD_SUCCESS; -} +} ALIAS (no_districute_list, no_ipv6_distribute_list_cmd, "no distribute-list WORD (in|out) WORD", @@ -472,7 +486,7 @@ DEFUN (districute_list_prefix_all, type = DISTRIBUTE_OUT; else { - vty_out (vty, "distribute list direction must be [in|out]%s", + vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE); return CMD_WARNING; } @@ -481,7 +495,7 @@ DEFUN (districute_list_prefix_all, dist = distribute_list_prefix_set (NULL, type, argv[0]); return CMD_SUCCESS; -} +} ALIAS (districute_list_prefix_all, ipv6_distribute_list_prefix_all_cmd, @@ -512,7 +526,7 @@ DEFUN (no_districute_list_prefix_all, type = DISTRIBUTE_OUT; else { - vty_out (vty, "distribute list direction must be [in|out]%s", + vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE); return CMD_WARNING; } @@ -524,7 +538,7 @@ DEFUN (no_districute_list_prefix_all, return CMD_WARNING; } return CMD_SUCCESS; -} +} ALIAS (no_districute_list_prefix_all, no_ipv6_distribute_list_prefix_all_cmd, @@ -555,7 +569,7 @@ DEFUN (districute_list_prefix, distribute_list_prefix_cmd, type = DISTRIBUTE_OUT; else { - vty_out (vty, "distribute list direction must be [in|out]%s", + vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE); return CMD_WARNING; } @@ -564,7 +578,7 @@ DEFUN (districute_list_prefix, distribute_list_prefix_cmd, dist = distribute_list_prefix_set (argv[2], type, argv[0]); return CMD_SUCCESS; -} +} ALIAS (districute_list_prefix, ipv6_distribute_list_prefix_cmd, "distribute-list prefix WORD (in|out) WORD", @@ -595,7 +609,7 @@ DEFUN (no_districute_list_prefix, no_distribute_list_prefix_cmd, type = DISTRIBUTE_OUT; else { - vty_out (vty, "distribute list direction must be [in|out]%s", + vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE); return CMD_WARNING; } @@ -607,7 +621,7 @@ DEFUN (no_districute_list_prefix, no_distribute_list_prefix_cmd, return CMD_WARNING; } return CMD_SUCCESS; -} +} ALIAS (no_districute_list_prefix, no_ipv6_distribute_list_prefix_cmd, "no distribute-list prefix WORD (in|out) WORD", @@ -714,7 +728,7 @@ config_write_distribute (struct vty *vty) if (dist->list[DISTRIBUTE_IN]) { - vty_out (vty, " distribute-list %s in %s%s", + vty_out (vty, " distribute-list %s in %s%s", dist->list[DISTRIBUTE_IN], dist->ifname ? dist->ifname : "", VTY_NEWLINE); @@ -723,7 +737,7 @@ config_write_distribute (struct vty *vty) if (dist->list[DISTRIBUTE_OUT]) { - vty_out (vty, " distribute-list %s out %s%s", + vty_out (vty, " distribute-list %s out %s%s", dist->list[DISTRIBUTE_OUT], dist->ifname ? dist->ifname : "", diff --git a/lib/if_rmap.c b/lib/if_rmap.c index ddc62fd5..dfb66260 100644 --- a/lib/if_rmap.c +++ b/lib/if_rmap.c @@ -16,7 +16,7 @@ * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. + * 02111-1307, USA. */ #include <zebra.h> @@ -32,7 +32,7 @@ struct hash *ifrmaphash; /* Hook functions. */ static void (*if_rmap_add_hook) (struct if_rmap *) = NULL; static void (*if_rmap_delete_hook) (struct if_rmap *) = NULL; - + static struct if_rmap * if_rmap_new (void) { @@ -63,11 +63,18 @@ if_rmap_lookup (const char *ifname) struct if_rmap key; struct if_rmap *if_rmap; - /* temporary copy */ - key.ifname = (char *)ifname; + union { + const char* waxon ; + char* waxoff ; + } miyagi ; + + miyagi.waxon = ifname ; + + /* temporary reference */ + key.ifname = miyagi.waxoff ; if_rmap = hash_lookup (ifrmaphash, &key); - + return if_rmap; } @@ -100,8 +107,15 @@ if_rmap_get (const char *ifname) { struct if_rmap key; - /* temporary copy */ - key.ifname = (char *)ifname; + union { + const char* waxon ; + char* waxoff ; + } miyagi ; + + miyagi.waxon = ifname ; + + /* temporary reference */ + key.ifname = miyagi.waxoff ; return (struct if_rmap *) hash_get (ifrmaphash, &key, if_rmap_hash_alloc); } @@ -127,9 +141,9 @@ if_rmap_hash_cmp (const void *arg1, const void* arg2) return strcmp (if_rmap1->ifname, if_rmap2->ifname) == 0; } - + static struct if_rmap * -if_rmap_set (const char *ifname, enum if_rmap_type type, +if_rmap_set (const char *ifname, enum if_rmap_type type, const char *routemap_name) { struct if_rmap *if_rmap; @@ -140,25 +154,25 @@ if_rmap_set (const char *ifname, enum if_rmap_type type, { if (if_rmap->routemap[IF_RMAP_IN]) XFREE (MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_IN]); - if_rmap->routemap[IF_RMAP_IN] + if_rmap->routemap[IF_RMAP_IN] = XSTRDUP (MTYPE_IF_RMAP_NAME, routemap_name); } if (type == IF_RMAP_OUT) { if (if_rmap->routemap[IF_RMAP_OUT]) XFREE (MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_OUT]); - if_rmap->routemap[IF_RMAP_OUT] + if_rmap->routemap[IF_RMAP_OUT] = XSTRDUP (MTYPE_IF_RMAP_NAME, routemap_name); } if (if_rmap_add_hook) (*if_rmap_add_hook) (if_rmap); - + return if_rmap; } static int -if_rmap_unset (const char *ifname, enum if_rmap_type type, +if_rmap_unset (const char *ifname, enum if_rmap_type type, const char *routemap_name) { struct if_rmap *if_rmap; @@ -175,7 +189,7 @@ if_rmap_unset (const char *ifname, enum if_rmap_type type, return 0; XFREE (MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_IN]); - if_rmap->routemap[IF_RMAP_IN] = NULL; + if_rmap->routemap[IF_RMAP_IN] = NULL; } if (type == IF_RMAP_OUT) @@ -186,7 +200,7 @@ if_rmap_unset (const char *ifname, enum if_rmap_type type, return 0; XFREE (MTYPE_IF_RMAP_NAME, if_rmap->routemap[IF_RMAP_OUT]); - if_rmap->routemap[IF_RMAP_OUT] = NULL; + if_rmap->routemap[IF_RMAP_OUT] = NULL; } if (if_rmap_delete_hook) @@ -227,7 +241,7 @@ DEFUN (if_rmap, if_rmap = if_rmap_set (argv[2], type, argv[0]); return CMD_SUCCESS; -} +} ALIAS (if_rmap, if_ipv6_rmap_cmd, @@ -268,7 +282,7 @@ DEFUN (no_if_rmap, return CMD_WARNING; } return CMD_SUCCESS; -} +} ALIAS (no_if_rmap, no_if_ipv6_rmap_cmd, @@ -279,7 +293,7 @@ ALIAS (no_if_rmap, "Route map for input filtering\n" "Route map for output filtering\n" "Route map interface name\n") - + /* Configuration write function. */ int config_write_if_rmap (struct vty *vty) @@ -297,7 +311,7 @@ config_write_if_rmap (struct vty *vty) if (if_rmap->routemap[IF_RMAP_IN]) { - vty_out (vty, " route-map %s in %s%s", + vty_out (vty, " route-map %s in %s%s", if_rmap->routemap[IF_RMAP_IN], if_rmap->ifname, VTY_NEWLINE); @@ -306,7 +320,7 @@ config_write_if_rmap (struct vty *vty) if (if_rmap->routemap[IF_RMAP_OUT]) { - vty_out (vty, " route-map %s out %s%s", + vty_out (vty, " route-map %s out %s%s", if_rmap->routemap[IF_RMAP_OUT], if_rmap->ifname, VTY_NEWLINE); diff --git a/lib/qafi_safi.h b/lib/qafi_safi.h index bf0f0360..40915ca5 100644 --- a/lib/qafi_safi.h +++ b/lib/qafi_safi.h @@ -118,6 +118,27 @@ enum qSAFI } ; /*============================================================================== + * iAFI_SAFI and qAFI_SAFI structures + */ +struct iAFI_SAFI +{ + iAFI_t afi ; + iSAFI_t safi ; +} ; + +typedef struct iAFI_SAFI iAFI_SAFI_t ; +typedef struct iAFI_SAFI* iAFI_SAFI ; + +struct qAFI_SAFI +{ + qAFI_t afi ; + qSAFI_t safi ; +} ; + +typedef struct qAFI_SAFI qAFI_SAFI_t ; +typedef struct qAFI_SAFI* qAFI_SAFI ; + +/*============================================================================== * Quagga AFI/SAFI values -- original macro definitions */ diff --git a/lib/stream.c b/lib/stream.c index dc636361..79ce1791 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -215,6 +215,13 @@ stream_get_endp (struct stream *s) } size_t +stream_get_left (struct stream *s) +{ + STREAM_VERIFY_SANE(s); + return s->endp - s->getp ; +} + +size_t stream_get_size (struct stream *s) { STREAM_VERIFY_SANE(s); diff --git a/lib/stream.h b/lib/stream.h index 957bf495..094cf0c6 100644 --- a/lib/stream.h +++ b/lib/stream.h @@ -143,6 +143,7 @@ extern struct stream* stream_dup_pending(struct stream*) ; extern size_t stream_resize (struct stream *, size_t); extern size_t stream_get_getp (struct stream *); extern size_t stream_get_endp (struct stream *); +extern size_t stream_get_left (struct stream *s) ; extern size_t stream_get_size (struct stream *); extern u_char *stream_get_data (struct stream *); |