diff options
author | Chris Hall <GMCH@hestia.halldom.com> | 2010-01-23 11:21:17 +0000 |
---|---|---|
committer | Chris Hall <GMCH@hestia.halldom.com> | 2010-01-23 11:21:17 +0000 |
commit | 0341d5ce47c301b4a4d92b77a83930da4fdc8fb3 (patch) | |
tree | acff360d75d85e711d65e8d4fbe5139bf19b25e0 | |
parent | eeda1184fa60c5077c2d404d0a8415d11e836ccd (diff) | |
download | quagga-0341d5ce47c301b4a4d92b77a83930da4fdc8fb3.tar.bz2 quagga-0341d5ce47c301b4a4d92b77a83930da4fdc8fb3.tar.xz |
Blitz on bgp_msg_read, particularly OPEN message handling
In the BGP Engine the OPEN message needs to be processed into the open_recv
structure in the *connection*. The OPEN that arrives must be checked
for acceptability before it is acknowledged. Later the connection may be
discarded in collision resolution, or the connection may become the
Established connection, and the open_recv structure is passed to the
session and hence to the Peering Engine.
modified: bgpd/bgp.h
modified: bgpd/bgp_common.c
modified: bgpd/bgp_common.h
modified: bgpd/bgp_connection.c
modified: bgpd/bgp_connection.h
modified: bgpd/bgp_fsm.c
modified: bgpd/bgp_msg_read.c
modified: bgpd/bgp_msg_read.h
modified: bgpd/bgp_msg_write.c
modified: bgpd/bgp_notification.c
modified: bgpd/bgp_notification.h
modified: bgpd/bgp_open.h
modified: bgpd/bgp_open_state.c
modified: bgpd/bgp_open_state.h
modified: bgpd/bgp_packet.c
modified: bgpd/bgp_session.h
modified: lib/distribute.c
modified: lib/if_rmap.c
modified: lib/qafi_safi.h
modified: lib/stream.c
modified: lib/stream.h
-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 *); |