summaryrefslogtreecommitdiffstats
path: root/bgpd/bgp_open_state.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_open_state.c')
-rw-r--r--bgpd/bgp_open_state.c457
1 files changed, 457 insertions, 0 deletions
diff --git a/bgpd/bgp_open_state.c b/bgpd/bgp_open_state.c
new file mode 100644
index 00000000..9ca9617e
--- /dev/null
+++ b/bgpd/bgp_open_state.c
@@ -0,0 +1,457 @@
+/* BGP Open State -- functions
+ * Copyright (C) 2009 Chris Hall (GMCH), Highwayman
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "zebra.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_peer.h"
+#include "bgpd/bgp_session.h"
+#include "bgpd/bgp_open_state.h"
+
+#include "lib/memory.h"
+
+/*==============================================================================
+ * BGP Open State.
+ *
+ * This structure encapsulates all the information that may be sent/received
+ * in a BGP OPEN Message.
+ *
+ */
+
+/*------------------------------------------------------------------------------
+ * Initialise new bgp_open_state structure -- allocate if required.
+ *
+ */
+extern bgp_open_state
+bgp_open_state_init_new(bgp_open_state state)
+{
+ if (state == NULL)
+ state = XCALLOC(MTYPE_BGP_OPEN_STATE, sizeof(struct bgp_open_state)) ;
+ else
+ memset(state, 0, sizeof(struct bgp_open_state)) ;
+
+ vector_init_new(&state->unknowns, 0) ;
+
+ return state ;
+}
+
+/*------------------------------------------------------------------------------
+ * Free bgp_open_state structure (if any)
+ *
+ * Returns NULL.
+ */
+extern bgp_open_state
+bgp_open_state_free(bgp_open_state state)
+{
+ bgp_cap_unknown unknown ;
+ bgp_cap_afi_safi afi_safi ;
+
+ if (state != NULL)
+ {
+ while ((unknown = vector_ream_keep(&state->unknowns)) != NULL)
+ XFREE(MTYPE_TMP, unknown) ;
+
+ while ((afi_safi = vector_ream_keep(&state->afi_safi)) != NULL)
+ XFREE(MTYPE_TMP, afi_safi) ;
+
+ XFREE(MTYPE_BGP_OPEN_STATE, state) ;
+ } ;
+
+ return NULL ;
+}
+
+/*------------------------------------------------------------------------------
+ * Unset pointer to open_state structure and free structure (if any).
+ */
+extern void
+bgp_open_state_unset(bgp_open_state* p_state)
+{
+ bgp_open_state_free(*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.
+ *
+ * Initialises the structure according to the current peer state.
+ */
+
+bgp_open_state
+bgp_peer_open_state_init_new(bgp_open_state state, bgp_peer peer)
+{
+ safi_t safi ;
+ afi_t afi ;
+
+ state = bgp_open_state_init_new(state) ; /* allocate if req. Zeroise. */
+
+ /* Choose the appropriate ASN */
+ if (peer->change_local_as)
+ state->my_as = peer->change_local_as ;
+ else
+ state->my_as = peer->local_as ;
+
+ /* Choose the appropriate hold time */
+ if (peer->config & PEER_CONFIG_TIMER)
+ state->holdtime = peer->holdtime ;
+ else
+ state->holdtime = peer->bgp->default_holdtime ;
+
+ /* Set our bgpd_id */
+ state->bgp_id = peer->local_id.s_addr ;
+
+ /* Whether to send capability or not */
+ state->can_capability = ! CHECK_FLAG(peer->flags, PEER_FLAG_DONT_CAPABILITY) ;
+
+ /* Announce self as AS4 speaker always */
+ if (!bm->as2_speaker)
+ SET_FLAG(peer->cap, PEER_CAP_AS4_ADV) ;
+ state->can_as4 = CHECK_FLAG(peer->cap, PEER_CAP_AS4_ADV) ? 1 : 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)
+ for (safi = qSAFI_min ; safi <= qSAFI_max ; ++safi)
+ if (peer->afc[afi][safi])
+ state->can_mp_ext |= qafx_bit(qafx_num_from_qAFI_qSAFI(afi, safi)) ;
+
+ /* Route refresh -- always */
+ SET_FLAG(peer->cap, PEER_CAP_REFRESH_ADV) ;
+ state->can_r_refresh = CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_ADV)
+ ? (bgp_form_pre | bgp_form_rfc)
+ : bgp_form_none ;
+
+ /* ORF capability. */
+ for (afi = qAFI_min ; afi <= qAFI_max ; ++afi)
+ for (safi = qSAFI_min ; safi <= qSAFI_max ; ++safi)
+ {
+ if (peer->af_flags[afi][safi] & PEER_FLAG_ORF_PREFIX_SM)
+ state->can_orf_prefix_send |=
+ qafx_bit(qafx_num_from_qAFI_qSAFI(afi, safi)) ;
+ if (peer->af_flags[afi][safi] & PEER_FLAG_ORF_PREFIX_RM)
+ state->can_orf_prefix_recv |=
+ qafx_bit(qafx_num_from_qAFI_qSAFI(afi, safi)) ;
+ } ;
+
+ state->can_orf_prefix = (state->can_orf_prefix_send |
+ state->can_orf_prefix_recv)
+ ? (bgp_form_pre | bgp_form_rfc)
+ : bgp_form_none ;
+
+ /* Dynamic Capabilities TODO: check requirement */
+ state->can_dynamic = ( CHECK_FLAG(peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY)
+ != 0 ) ;
+ if (state->can_dynamic)
+ SET_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV) ;
+
+ /* Graceful restart capability */
+ if (bgp_flag_check(peer->bgp, BGP_FLAG_GRACEFUL_RESTART))
+ {
+ SET_FLAG(peer->cap, PEER_CAP_RESTART_ADV) ;
+ state->can_g_restart = 1 ;
+ state->restart_time = peer->bgp->restart_time ;
+ }
+ else
+ {
+ state->can_g_restart = 0 ;
+ state->restart_time = 0 ;
+ } ;
+
+ /* 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->has_restarted = 0 ; /* has not restarted */
+
+ return state;
+}
+
+/*==============================================================================
+ * Unknown capabilities handling.
+ *
+ */
+
+/*------------------------------------------------------------------------------
+ * Add given unknown capability and its value to the given open_state.
+ */
+extern void
+bgp_open_state_unknown_add(bgp_open_state state, uint8_t code,
+ void* value, bgp_size_t length)
+{
+ bgp_cap_unknown unknown ;
+
+ unknown = XCALLOC(MTYPE_TMP, sizeof(struct bgp_cap_unknown) + length) ;
+
+ unknown->code = code ;
+ unknown->length = length ;
+
+ if (length != 0)
+ memcpy(unknown->value, value, length) ;
+
+ vector_push_item(&state->unknowns, unknown) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Get count of number of unknown capabilities in given open_state.
+ */
+extern int
+bgp_open_state_unknown_count(bgp_open_state state)
+{
+ return vector_end(&state->unknowns) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Get n'th unknown capability -- if exists.
+ */
+extern bgp_cap_unknown
+bgp_open_state_unknown_cap(bgp_open_state state, unsigned index)
+{
+ return vector_get_item(&state->unknowns, index) ;
+} ;
+
+/*==============================================================================
+ * Generic afi/safi capabilities handling.
+ *
+ */
+
+/*------------------------------------------------------------------------------
+ * Add given afi/safi capability and its value to the given open_state.
+ */
+extern bgp_cap_afi_safi
+bgp_open_state_afi_safi_add(bgp_open_state state, iAFI_t afi, iSAFI_t safi,
+ bool known, uint8_t cap_code)
+{
+ bgp_cap_afi_safi afi_safi ;
+
+ afi_safi = XCALLOC(MTYPE_TMP, sizeof(struct bgp_cap_afi_safi)) ;
+
+ afi_safi->known_afi_safi = known ;
+ afi_safi->afi = afi ;
+ afi_safi->safi = safi ;
+ afi_safi->cap_code = cap_code ;
+
+ vector_push_item(&state->afi_safi, afi_safi) ;
+
+ return afi_safi ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Get count of number of afi/safi capabilities in given open_state.
+ */
+extern int
+bgp_open_state_afi_safi_count(bgp_open_state state)
+{
+ return vector_end(&state->afi_safi) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Get n'th afi_safi capability -- if exists.
+ */
+extern bgp_cap_afi_safi
+bgp_open_state_afi_safi_cap(bgp_open_state state, unsigned index)
+{
+ return vector_get_item(&state->afi_safi, index) ;
+} ;
+
+/*==============================================================================
+ *
+ */
+
+/* Received an open, update the peer's state
+ *
+ * Takes the peer->session->open_recv and fills in:
+ *
+ * peer->v_holdtime ) per negotiated values
+ * peer->v_keepalive )
+ *
+ * peer->remote_id.s_addr
+ *
+ * peer->cap ) updated per open_recv -- assumes all recv flags
+ * peer->af_cap ) have been cleared.
+ *
+ * peer->v_gr_restart set to value received (if any)
+ *
+ * peer->afc_recv set/cleared according to what is advertised
+ * BUT if !open_recv->can_capability or
+ * neighbor override-capability, then
+ * all flags are cleared.
+ *
+ * peer->afc_nego set/cleared according to what is advertised and
+ * what is activated.
+ * BUT if !open_recv->can_capability or
+ * neighbor override-capability, then
+ * set everything which has been activated.
+ *
+ *
+ *
+ * NB: for safety, best to have the session locked -- though won't, in fact,
+ * change any of this information after the session is established.
+ */
+void
+bgp_peer_open_state_receive(bgp_peer peer)
+{
+ bgp_session session = peer->session;
+ bgp_open_state open_recv = session->open_recv;
+ qAFI_t afi;
+ qSAFI_t safi;
+ qafx_bit_t qbs ;
+ int recv ;
+
+ /* Check neighbor as number. */
+ assert(open_recv->my_as == peer->as);
+
+ /* If had to suppress sending of capabilities, note that */
+ if (session->cap_suppress)
+ SET_FLAG (peer->cap, PEER_CAP_SUPPRESSED) ;
+
+ /* holdtime */
+ /* From the rfc: A reasonable maximum time between KEEPALIVE messages
+ would be one third of the Hold Time interval. KEEPALIVE messages
+ MUST NOT be sent more frequently than one per second. An
+ implementation MAY adjust the rate at which it sends KEEPALIVE
+ messages as a function of the Hold Time interval. */
+
+ /* The BGP Engine sets the session's HoldTimer and KeepaliveTimer intervals
+ * to the values negotiated when the OPEN messages were exchanged.
+ *
+ * Take copies of that information.
+ */
+ peer->v_holdtime = session->hold_timer_interval ;
+ peer->v_keepalive = session->keepalive_timer_interval ;
+
+ /* Set remote router-id */
+ peer->remote_id.s_addr = open_recv->bgp_id;
+
+ /* AS4 */
+ if (open_recv->can_as4)
+ SET_FLAG (peer->cap, PEER_CAP_AS4_RCV);
+
+ /* AFI/SAFI -- as received, or assumed or overridden */
+
+ if (!open_recv->can_capability || session->cap_override)
+ {
+ /* There were no capabilities, or are OVERRIDING AFI/SAFI, so force
+ * not having received any AFI/SAFI, but apply all known.
+ */
+ recv = 0 ;
+ qbs = qafx_known_bits ;
+ }
+ else
+ {
+ /* Use the AFI/SAFI received, if any. */
+ recv = 1 ;
+ qbs = open_recv->can_mp_ext ;
+ }
+
+ for (afi = qAFI_min ; afi <= qAFI_max ; ++afi)
+ for (safi = qSAFI_min ; safi <= qSAFI_max ; ++safi)
+ {
+ qafx_bit_t qb = qafx_bit_from_qAFI_qSAFI(afi, safi) ;
+ if (qb & qbs)
+ {
+ peer->afc_recv[afi][safi] = recv ;
+ peer->afc_nego[afi][safi] = peer->afc[afi][safi] ;
+ }
+ else
+ {
+ peer->afc_recv[afi][safi] = 0 ;
+ peer->afc_nego[afi][safi] = 0 ;
+ } ;
+ } ;
+
+ /* Route refresh. */
+ if (open_recv->can_r_refresh & bgp_form_pre)
+ SET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV);
+ else if (open_recv->can_r_refresh & bgp_form_rfc)
+ SET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV);
+
+ /* ORF */
+ for (afi = qAFI_min ; afi <= qAFI_max ; ++afi)
+ for (safi = qSAFI_min ; safi <= qSAFI_max ; ++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)
+ SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV);
+ }
+
+ /* ORF prefix. */
+ if (open_recv->can_orf_prefix_send)
+ {
+ if (open_recv->can_orf_prefix & bgp_form_pre)
+ SET_FLAG (peer->cap, PEER_CAP_ORF_PREFIX_SM_OLD_RCV);
+ else if (open_recv->can_orf_prefix & bgp_form_rfc)
+ SET_FLAG (peer->cap, PEER_CAP_ORF_PREFIX_SM_RCV);
+ }
+ if (open_recv->can_orf_prefix_recv)
+ {
+ if (open_recv->can_orf_prefix & bgp_form_pre)
+ SET_FLAG (peer->cap, PEER_CAP_ORF_PREFIX_RM_OLD_RCV);
+ else if (open_recv->can_orf_prefix & bgp_form_rfc)
+ SET_FLAG (peer->cap, PEER_CAP_ORF_PREFIX_RM_RCV);
+ }
+
+ /* Dynamic Capabilities */
+ if (open_recv->can_dynamic)
+ SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV);
+
+ /* Graceful restart
+ *
+ * NB: appear not to care about open_recv->has_restarted !
+ */
+ if (open_recv->can_g_restart)
+ SET_FLAG (peer->cap, PEER_CAP_RESTART_RCV) ;
+
+ for (afi = qAFI_min ; afi <= qAFI_max ; ++afi)
+ for (safi = qSAFI_min ; safi <= qSAFI_max ; ++safi)
+ {
+ qafx_bit_t qb = qafx_bit_from_qAFI_qSAFI(afi, safi);
+ if (peer->afc[afi][safi] && (qb & open_recv->can_preserve))
+ {
+ SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV);
+ if (qb & open_recv->has_preserved)
+ SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV);
+ }
+ }
+
+ peer->v_gr_restart = open_recv->restart_time;
+ /* TODO: should we do anything with this? */
+#if 0
+ int restarting ; /* Restart State flag */
+#endif
+}